
* init scaled changes * add correct padding values for M3 * revert unneeded change * Update packages/flutter/lib/src/material/text_button.dart Co-authored-by: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> * Update packages/flutter/lib/src/material/text_button.dart Co-authored-by: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> * comment fixes * test update * docstring fixes * e44a0de4c Roll Fuchsia Mac SDK from JLTTlcNPJeScjSO2B... to FeFYsNPy64-PEXPer... (flutter/engine#38558) (#117779) * Roll Plugins from e11cb245bb8e to 2d66f30e5825 (2 revisions) (#117781) * 417b37009 Roll Flutter from ae292cc4e5e4 to 17482fd425ee (28 revisions) (flutter/plugins#6889) * 2d66f30e5 [webview_flutter_web] Adds auto registration of the `WebViewPlatform` implementation (flutter/plugins#6886) * 4dd8a694f Roll Skia from cc3e0cd0a743 to c776239198f7 (1 revision) (flutter/engine#38560) (#117783) * 3460f349b [fuchsia] Set presentation interval (flutter/engine#38549) (#117785) * Roll Flutter Engine from 3460f349b01d to 1752b5b84680 (2 revisions) (#117788) * 332c0a2f2 Roll Skia from c776239198f7 to 13435162b783 (1 revision) (flutter/engine#38561) * 1752b5b84 Roll Dart SDK from 7f154f949aaf to fa6cf7241184 (2 revisions) (flutter/engine#38563) * a63bd854a [fuchsia] Add trace flow for Flatland::Present (flutter/engine#38565) (#117790) * Roll Flutter Engine from a63bd854ac5a to 5713a216076f (2 revisions) (#117795) * e012dc825 [Windows] Add engine builder to simplify tests (flutter/engine#38546) * 5713a2160 Revert "[web] Don't overwrite editing state with semantic updates (#38271)" (flutter/engine#38562) * Roll Flutter Engine from 5713a216076f to 780082203ea9 (2 revisions) (#117797) * fd94b04b1 [Impeller Scene] Import skinned mesh vertex data (flutter/engine#38554) * 780082203 Roll Fuchsia Linux SDK from gnyHyot4AZp7HZgUI... to KCm_e3N4gosNuY4IW... (flutter/engine#38568) * 9095f7a8b Roll Dart SDK from fa6cf7241184 to 224ac5ed9c66 (1 revision) (flutter/engine#38569) (#117799) * 0118b461b Roll Fuchsia Mac SDK from FeFYsNPy64-PEXPer... to 2lzQU8FEjR5AkOr4d... (flutter/engine#38571) (#117800) * e03d7c8bb Roll Skia from 13435162b783 to 9e8f31e3020c (3 revisions) (flutter/engine#38572) (#117802) * af6078b5f Roll Skia from 9e8f31e3020c to 486deb23bc2a (2 revisions) (flutter/engine#38574) (#117804) * 7e5cc7bb6 Roll Dart SDK from 224ac5ed9c66 to 9f0d8b9f20da (1 revision) (flutter/engine#38575) (#117805) * d4a04a538 Roll Fuchsia Linux SDK from KCm_e3N4gosNuY4IW... to IApTRqW8UUSWAOcqA... (flutter/engine#38578) (#117817) * b202b3db9 Roll Flutter from 17482fd425ee to d2127ad344e8 (14 revisions) (flutter/plugins#6892) (#117824) * Roll Flutter Engine from d4a04a538050 to 9153966bcb06 (2 revisions) (#117830) * 53806fa1e Roll Fuchsia Mac SDK from 2lzQU8FEjR5AkOr4d... to Bewt-eq7gNu6sU_Ob... (flutter/engine#38579) * 9153966bc [fuchsia] Bump the target API level to 11 (flutter/engine#38544) * b9bf51d16 Roll Dart SDK from 9f0d8b9f20da to 881c0b56a1f7 (1 revision) (flutter/engine#38580) (#117832) * Roll Flutter Engine from b9bf51d16f25 to f6ad9b6d00e3 (2 revisions) (#117834) * 4b38736e7 [Impeller Scene] Import materials, load embedded textures (flutter/engine#38577) * f6ad9b6d0 Roll Fuchsia Linux SDK from IApTRqW8UUSWAOcqA... to CXcPP_JZKQbSu2eIP... (flutter/engine#38581) * 932591ec0 Roll Fuchsia Linux SDK from CXcPP_JZKQbSu2eIP... to PkN8FdI4aC9z7W4mI... (flutter/engine#38584) (#117840) * 3d8c5ef10 Roll Fuchsia Linux SDK from PkN8FdI4aC9z7W4mI... to OOL-jWRElkQ2P3vJz... (flutter/engine#38585) (#117846) * Roll Flutter Engine from 3d8c5ef1060c to a7decc3e459b (2 revisions) (#117856) * 3470fa848 Roll Skia from 486deb23bc2a to a31d9c3b4583 (2 revisions) (flutter/engine#38586) * a7decc3e4 Roll Skia from a31d9c3b4583 to 01aeec883a43 (4 revisions) (flutter/engine#38587) * 0a2029cf3 Roll Fuchsia Linux SDK from OOL-jWRElkQ2P3vJz... to AE3lAqTc632VsY14L... (flutter/engine#38588) (#117858) * 5fe7d5b4e Roll Skia from 01aeec883a43 to 2ffa04c2f77c (2 revisions) (flutter/engine#38591) (#117863) * e5d605b3a Roll Skia from 2ffa04c2f77c to 269dce7e16bb (1 revision) (flutter/engine#38592) (#117865) * 71c5f1704 Roll Fuchsia Linux SDK from AE3lAqTc632VsY14L... to UAq0LO56_kbgA_BUQ... (flutter/engine#38593) (#117868) * 472e34cbb Roll Skia from 269dce7e16bb to fde37f5986fd (1 revision) (flutter/engine#38594) (#117869) * Roll Plugins from b202b3db98dc to e85f8ac1502d (3 revisions) (#117875) * 035d85e62 Roll Flutter from d2127ad344e8 to 120058fd3ded (15 revisions) (flutter/plugins#6896) * 80532e0ba Roll Flutter from 120058fd3ded to 0196e6050b75 (3 revisions) (flutter/plugins#6901) * e85f8ac15 Roll Flutter from 0196e6050b75 to b938dc13df32 (7 revisions) (flutter/plugins#6908) * [flutter_tools] timeline_test.dart flaky (#116667) * contains name instead of remove last * fix expect * remove and expect on elements * delete unused code * 7e51aef0a Roll Skia from fde37f5986fd to 809e328ed55c (1 revision) (flutter/engine#38596) (#117874) * Updated to tokens v0.150. (#117350) * Updated to tokens v0.150. * Updated with a reverted list_tile.dart. * Simplify null check. (#117026) * Simplify null check. * Simplify null check. * Simplify null check. * Fix. * Roll Flutter Engine from 7e51aef0a1be to 1d2ba73d1059 (9 revisions) (#117923) * 3e1b0dcb2 Roll Dart SDK from 881c0b56a1f7 to 617e70c95f5b (1 revision) (flutter/engine#38597) * 8b17efed8 Roll Fuchsia Linux SDK from UAq0LO56_kbgA_BUQ... to LA5kW39Gec7KvvM7x... (flutter/engine#38598) * 27960a700 [Impeller Scene] Import animation data (flutter/engine#38583) * b5acb2099 Roll Skia from 809e328ed55c to 697f9b541a0e (1 revision) (flutter/engine#38599) * dd0335b34 Roll Skia from 697f9b541a0e to 15d36b15bca1 (1 revision) (flutter/engine#38601) * adda2e80c [Impeller Scene] Animation binding and playback (flutter/engine#38595) * 71a296d53 Roll Fuchsia Linux SDK from LA5kW39Gec7KvvM7x... to rPo4_TYHCtkoOfRup... (flutter/engine#38607) * bde8d4524 Implement ITextProvider and ITextRangeProvider for UIA (flutter/engine#38538) * 1d2ba73d1 [Windows] Make the engine own the cursor plugin (flutter/engine#38570) * Reland "Remove single-view assumption from ScrollPhysics (#117503)" (#117916) This reverts commit c956121ac098b91061bfc0a93c930121ff3279ba. * Minor documentation fix on BorderRadiusDirectional.zero (#117661) * fix typos (#117592) * c0b3f8fce Make `AccessibilityBridge` a `AXPlatformTreeManager` (flutter/engine#38610) (#117931) * Add convenience constructors for SliverList (#116605) * init * lint * add the other two slivers * fix lint * add test for sliverlist.separated * add3 more * fix lint and tests * remove trailing spaces * remove trailing spaces 2 * fix lint * fix lint again * 2213b80dd [Impeller Scene] Use std::chrono for animation durations (flutter/engine#38606) (#117935) * Reland "Add support for double tap and drag for text selection #109573" (#117502) * Revert "Revert "Add support for double tap and drag for text selection (#109573)" (#117497)" This reverts commit 39fa0117a919bd401c4c8734c97ddb46fbc45cb7. * Allow TapAndDragGestureRecognizer to accept pointer events from any devices -- the TapGestureRecognizer it replaces was previously doing this Co-authored-by: Renzo Olivares <roliv@google.com> * == override parameters are non-nullable (#117839) * Fix the message strings for xcodeMissing and xcodeIncomplete (#117922) * Add macOS to xcodeMissing and xcodeIncomplete * And unit test * 32c468507 Roll quiver to 3.2.1 (flutter/engine#38617) (#117942) * Send text direction in selection rects (#117436) * Correctly propagate verbosity to subtasks in flutter.gradle (#117897) * Correctly propagate verbosity to subtasks in flutter.gradle * Add test * Revert accidental changes * Fix copyright year * Fix imports * Roll Plugins from e85f8ac1502d to f9dda6a27b79 (3 revisions) (#117972) * 6df3ef23f [in_app_pur] Add screenshots to pubspec.yaml (flutter/plugins#6540) * 42f8093c2 [google_maps_flutter] Fixed minor syntax error in the README.md (flutter/plugins#6909) * f9dda6a27 [image_picker_ios] Fix FLTPHPickerSaveImageToPathOperation property attributes (flutter/plugins#6890) * [flutter_tools] Fix null check in parsing web plugin from pubspec.yaml (#117939) * fix null check in parsing web plugin yaml * revert accidental diff * remove comment * roll packages (#117940) * roll packages (#118001) * [Android] Increase timeout duration for spell check integration test (#117989) * Add timeout * Add library directive * Add comment, remove testing only changes * Roll Flutter Engine from 32c468507b32 to cdd3bf29e27a (8 revisions) (#118014) * 22f872d5e Roll Dart SDK from 617e70c95f5b to f6dcb8b0b5d3 (7 revisions) (flutter/engine#38626) * c5e0f9ed0 Roll Dart SDK from f6dcb8b0b5d3 to 0b064bc49557 (1 revision) (flutter/engine#38630) * 398f5d3bd Roll Skia from 15d36b15bca1 to 9423a8a0fc2d (37 revisions) (flutter/engine#38631) * ebf01dcdb Update FlutterPlatformNodeDelegate (flutter/engine#38615) * d7dbe5bf3 Roll Skia from 9423a8a0fc2d to 60e4a4a27375 (5 revisions) (flutter/engine#38633) * 67440ccd5 fix roll (flutter/engine#38635) * 87bdde8fe Fix build using VS 17.4's C++ STL (flutter/engine#38614) * cdd3bf29e make DisplayListFlags constexpr throughout (flutter/engine#38649) * 60515762e [Impeller Scene] Compute joint transforms and apply them to skinned meshes (flutter/engine#38628) (#118016) * 35b7dee32 [Impeller] Set adaptive tolerance when rendering FillPathGeometry (flutter/engine#38497) (#118017) * b9b0193ea Roll Skia from 60e4a4a27375 to 158d51b34caa (19 revisions) (flutter/engine#38654) (#118018) * a01548f5f [Impeller Scene] Fix material/vertex color overlapping (flutter/engine#38653) (#118027) * Roll Plugins from f9dda6a27b79 to 320461910156 (2 revisions) (#118040) * 365332fe1 Roll Flutter from b938dc13df32 to 231855fc87d0 (19 revisions) (flutter/plugins#6913) * 320461910 Update image_picker_ios CODEOWNER (flutter/plugins#6891) * 072a9ca37 Add `TextProvider` and `TextEdit` patterns to `AXPlatformNodeWin` (flutter/engine#38646) (#118039) * bb4015269 Roll Skia from 158d51b34caa to ecd3a2f865ba (1 revision) (flutter/engine#38659) (#118042) * Avoid using `TextAffinity` in `TextBoundary` (#117446) * Avoid affinity like the plague * ignore lint * clean up * fix test * review * Move wordboundary to text painter * docs * fix tests * 74861f369 Reduce the size of Overlay FlutterImageView in HC mode (flutter/engine#38393) (#118048) * 5bd90d6e7 Consider more roles as text (flutter/engine#38645) (#118049) * [EMPTY] Commit to refresh the tree that is currently red (#118062) * Remove doc reference to the deprecated ui.FlutterWindow API (#118064) * Fix `flutter update-packages` regression by fixing parameters in "pub get" runner (#116687) * Make pub get runner respect printProgress and retry parameters * Fix typo * Add regression test * Improve test * Fix implementation and test * Test to fix flutter_drone tests * Revert test * Attempt #2 to fix flutter_drone tests * Revert attempt * Hack: Force printProgress to debug Windows tests * Use ProcessUtils.run to avoid dangling stdout and stderr * Update documentation * Clean up retry argument * Adding 'is' to list of kotlin reserved keywords (#116299) Co-authored-by: Gray Mackall <mackall@google.com> * Added expandIconColor property on ExpansionPanelList Widget (#115950) * Create expanIconColor doc template * Add expandIconColor property to ExpansionPanelList * Added tests for expandIconColor on ExpansionPanelList & radio * Removed trailing spaces * Update docstring (#118072) Co-authored-by: a-wallen <stephenwallen@google.com> * Fix out-of-sync ExpansionPanel animation (#105024) * Increase minimum height of headerWidget in ExpansionPanel to smooth the animation. Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Add regression tests that check for equal height of header elements in ExpansionPanel. Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Clarify comment. Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Reduce padding in ExpandIcon to 12px s.t. header height is 48px. Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Update testcases to new header height (56px -> 48px). Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Test for header height equal to 48px. Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Change issue number to link in comment * Add periods to comments Signed-off-by: Morris Kurz <morriskurz@gmail.com> * Roll Plugins from 320461910156 to 276cfd4b212d (2 revisions) (#118099) * 3a6f63bed Roll Flutter from 231855fc87d0 to 43b912090224 (11 revisions) (flutter/plugins#6918) * 276cfd4b2 [shared_preferences] Convert macOS to Pigeon (flutter/plugins#6914) * 33d7f8a1b Remove single view assumptions from `window.dart` (flutter/engine#38453) (#118069) * InteractiveViewer parameter to return to pre-3.3 trackpad/Magic Mouse behaviour (#114280) * trackpadPanShouldActAsZoom * Address feedback * Move constant, add blank lines * 0a0e3d205 Roll Flutter from 43b912090224 to 507062032fa4 (9 revisions) (flutter/plugins#6919) (#118183) * Roll Flutter Engine from 33d7f8a1b307 to 03609b420beb (6 revisions) (#118125) * c58254702 SkBudgeted -> skgpu::Budgeted (flutter/engine#38660) * 3d9214ace Bump actions/checkout from 3.1.0 to 3.2.0 (flutter/engine#38390) * a4775c7a7 Remove strict equality check for SkMatrix comparison (flutter/engine#38665) * 046012e8e [fuchsia] Enable CI for branches like `fuchsia_r51a`. (flutter/engine#38683) * cda410c28 Roll Skia from ecd3a2f865ba to 54dbda290908 (12 revisions) (flutter/engine#38668) * 03609b420 [web] Fix canvas2d leaks in text measurement (flutter/engine#38640) * remove the unused check in selectable_text (#117716) * Roll Flutter Engine from 03609b420beb to b5513d7a442a (2 revisions) (#118186) * fd5a96e10 Limit selection change to focused node on Windows (flutter/engine#38634) * b5513d7a4 Roll Dart SDK from 0b064bc49557 to cb29cb6d1d0f (12 revisions) (flutter/engine#38688) * Roll Flutter Engine from b5513d7a442a to 5bdb04f33f99 (2 revisions) (#118187) * e20809014 Roll Skia from 54dbda290908 to b8c0a78a2378 (43 revisions) (flutter/engine#38690) * 5bdb04f33 Roll Fuchsia Mac SDK from Bewt-eq7gNu6sU_Ob... to ORxExaprF9fW5d4MP... (flutter/engine#38697) * 51baed6e0 [fuchsia][scenic] Use infinite hit region (flutter/engine#38647) (#118189) * Update to Xcode 14.2 (#117507) * Update to Xcode 14.2 * Only bump for devicelab builders * Restore presubmit: false * Allow iOS and macOS plugins to share darwin directory (#115337) * Roll Flutter Engine from 51baed6e01b8 to 5df0072a0e63 (3 revisions) (#118192) * 181286315 Roll Dart SDK from cb29cb6d1d0f to 853eff8b0faa (2 revisions) (flutter/engine#38694) * 642f72f73 Bump actions/upload-artifact from 3.1.0 to 3.1.2 (flutter/engine#38713) * 5df0072a0 Bump actions/checkout from 3.2.0 to 3.3.0 (flutter/engine#38714) * Use program during attach if provided (#118130) * eb5c6f0b4 iOS FlutterTextureRegistry should be a proxy, not the engine itself (flutter/engine#37666) (#118197) * Update `ListTile` to support Material 3 (#117965) * Update `ListTile` to support Material 3 * Update `Default ListTile debugFillProperties` * Add #99933 HTML workaround. * 3a7d8862f Re-enable UIA text/range provider unit tests (flutter/engine#38718) (#118201) * Fix path for require.js (#118120) - Matches new location in the Dart SDK. https://dart-review.googlesource.com/c/sdk/+/275482 - Includes fall back logic so the existing and new locations will work depending on the file that is available. * ee0c4d26b Roll flutter/packages to 25454e (flutter/engine#38685) (#118205) * Roll Flutter Engine from ee0c4d26b0fa to 264aa032cf75 (2 revisions) (#118208) * 5a39a8846 Add CI builder for windows-arm64. (flutter/engine#38394) * 264aa032c Revert "Add CI builder for windows-arm64. (#38394)" (flutter/engine#38729) * 9c0b187a1 Roll Dart SDK from 853eff8b0faa to 418bee5da2e2 (4 revisions) (flutter/engine#38727) (#118210) * add closed/open focus traversal; use open on web (#115961) * allow focus to leave FlutterView * fix tests and docs * small doc update * fix analysis lint * use closed loop for dialogs * add tests for new API * address comments * test FocusScopeNode.traversalEdgeBehavior setter; reverse wrap-around * rename actionResult to invokeResult * address comments * Roll Flutter Engine from 9c0b187a1139 to 716bb9172c0d (3 revisions) (#118220) * b6720a5b7 Undo axes flip on Mac when shift+scroll-wheel (flutter/engine#38338) * 4f0cdcd0b Inline usage of SkIsPow2 (flutter/engine#38722) * 716bb9172 [Impeller Scene] Add DisplayList OP and Dart bindings (flutter/engine#38676) * Hide InkWell hover highlight when an hovered InkWell is disabled (#118026) * Allow select cases to be numbers (#116625) * [Impeller Scene] Add SceneC asset importing (#118157) * Add a comment about repeat event + fix typos (#118095) * Add MaterialStateProperty `overlayColor` & `mouseCursor` and fix hovering on thumbs behavior (#116894) * Roll Flutter Engine from 716bb9172c0d to 687e3cb0fbe2 (2 revisions) (#118242) * 24ee5c10f Roll Fuchsia Mac SDK from ORxExaprF9fW5d4MP... to zC90VpkAGMG1jJ-BK... (flutter/engine#38734) * 687e3cb0f Roll Dart SDK from 418bee5da2e2 to 8d7a6aabd3a3 (2 revisions) (flutter/engine#38738) * Roll Plugins from 0a0e3d205ca3 to 9fdc899b72ca (8 revisions) (#118253) * d03de2fce [tool] Don't add Guava in the all-packages app (flutter/plugins#6747) * d485c7e83 [local_auth]: Bump espresso-core (flutter/plugins#6925) * a47e71988 [webview_flutter_platform_interface] Improves error message when `WebViewPlatform.instance` is null (flutter/plugins#6938) * 7132dac0e [google_maps]: Bump espresso-core from 3.4.0 to 3.5.1 in /packages/google_maps_flutter/google_maps_flutter_android/android (flutter/plugins#6937) * dc3287ccf [espresso]: Bump truth from 1.4.0 to 1.5.0 in /packages/espresso/android (flutter/plugins#6707) * 1de6477bd [camera]: Bump camerax_version from 1.3.0-alpha01 to 1.3.0-alpha02 in /packages/camera/camera_android_camerax/android (flutter/plugins#6828) * fb405819e [shared_preferences] Merge iOS and macOS implementations (flutter/plugins#6920) * 9fdc899b7 [various] Enable `avoid_dynamic_calls` (flutter/plugins#6834) * Manually mark Windows run_debug_test_windows as unflaky (#118112) * Marks Mac_arm64_android run_debug_test_android to be unflaky (#117469) * Marks Mac_arm64_ios run_debug_test_macos to be unflaky (#117990) * remove unsound mode web test (#118256) * Update `CupertinoPicker` example (#118248) * Update `CupertinoPicker` example * format lines * Revert making variable public * revert variable change * roll packages (#118117) * Add option for opting out of enter route snapshotting. (#118086) * Add option for opting out of enter route snapshotting. * Fix typo. * Merge find layers logic. * Add justification comment on why web is skipped in test. * Update documentation as suggested. * Update documentation as suggested. * roll packages (#118272) * Roll Flutter Engine from 687e3cb0fbe2 to c1d61cf11da8 (6 revisions) (#118274) * ad9052a38 Roll Dart SDK from 8d7a6aabd3a3 to b90a008ddb29 (1 revision) (flutter/engine#38740) * c4c97023f Mark nodes as `kIsLineBreakingObject` by default, TODO further distinctions (flutter/engine#38721) * f40af3eb4 Roll Dart SDK from b90a008ddb29 to 5e344de60564 (1 revision) (flutter/engine#38744) * 41cfbdd7e Roll Fuchsia Mac SDK from zC90VpkAGMG1jJ-BK... to 6xysoRPCXJ3cJX12x... (flutter/engine#38746) * 95c7b1f8a Make operator == parameter non-nullable (flutter/engine#38663) * c1d61cf11 Move canvaskit artifacts to expected location in Web SDK Archive (flutter/engine#38168) * Align `flutter pub get/upgrade/add/remove/downgrade` (#117896) * Align `flutter pub get/upgrade/add/remove/downgrade` * Add final . to command description * Remove trailing whitespace * Don't print message that command is being run * Update expectations * Use relative path * Remove duplicated line * Improve function dartdoc * ae9e181e3 Roll Dart SDK from 5e344de60564 to 7b4d49402252 (1 revision) (flutter/engine#38756) (#118287) * Fix Finnish TimeOfDate format (#118204) * init * add test * Roll Flutter Engine from ae9e181e30c2 to 53bd4bbf9646 (3 revisions) (#118289) * b9a723482 [web] retain GL/Gr context on window resize (flutter/engine#38576) * fd4360671 Add SpringAnimation.js from React Native (flutter/engine#38750) * 53bd4bbf9 Roll Skia from b8c0a78a2378 to e1f3980272f3 (24 revisions) (flutter/engine#38758) * 9ade91c8b removed forbidden skia include (flutter/engine#38761) (#118296) * 8d7beac82 Roll Dart SDK from 7b4d49402252 to 23cbd61a1327 (1 revision) (flutter/engine#38764) (#118297) * 6256f05db Roll Fuchsia Mac SDK from 6xysoRPCXJ3cJX12x... to a9NpYJbjhDRX9P9u4... (flutter/engine#38767) (#118300) * FIX: UnderlineInputBorder hashCode and equality by including borderRadius (#118284) * Bump actions/upload-artifact from 3.1.1 to 3.1.2 (#118116) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](83fd05a356...0b7f8abb15
) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/checkout from 3.1.0 to 3.3.0 (#118052) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.3.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](93ea575cb5...ac59398561
) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump github/codeql-action from 2.1.35 to 2.1.37 (#117104) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.1.35 to 2.1.37. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](b2a92eb56d...959cbb7472
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * 6048f9110 Roll Dart SDK from 23cbd61a1327 to 22fa50e09ee8 (3 revisions) (flutter/engine#38776) (#118320) * Roll Plugins from 9fdc899b72ca to 620a059d62b2 (4 revisions) (#118317) * 6a24f2d7b == override parameters are non-nullable (flutter/plugins#6900) * b9206bcfe [espresso]: Bump espresso-accessibility and espresso-idling-resource from 3.1.0 to 3.5.1 in /packages/espresso/android (flutter/plugins#6933) * b1797c2bb [file_selector] Switch to Pigeon for macOS (flutter/plugins#6902) * 620a059d6 [google_sign_in] Renames generated folder to js_interop. (flutter/plugins#6915) * ee76ab71e Cleanup Skia includes in image_generator/descriptor (flutter/engine#38775) (#118335) * Roll Flutter Engine from ee76ab71e0a6 to cccaae2f3d8b (3 revisions) (#118349) * 5ec03d7d1 Roll Fuchsia Mac SDK from a9NpYJbjhDRX9P9u4... to ao8fSjW8HrZSsu3yq... (flutter/engine#38782) * 87ead948e delete include of private GrMtlTypes header (flutter/engine#38783) * cccaae2f3 [fuchsia] Replace deprecated AddLocalChild (flutter/engine#38788) * 764a9e012 Roll Skia from e1f3980272f3 to dfb838747295 (48 revisions) (flutter/engine#38790) (#118355) * Roll Flutter Engine from 764a9e01204d to 4a8d6866a1c0 (2 revisions) (#118357) * 7abc5f13a [web] Update felt to use generated JS runtime for Dart2Wasm. (flutter/engine#38786) * 4a8d6866a Add CI builder for windows-arm64. (#38394) (flutter/engine#38739) * Marks Mac_ios complex_layout_scroll_perf_bad_ios__timeline_summary to be unflaky (#111570) * Marks Mac channels_integration_test to be unflaky (#111571) * Marks Mac_ios platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary to be unflaky (#116668) * Fix `SliverAppBar.large` and `SliverAppBar.medium` do not use `foregroundColor` (#118322) * docs: update docs about color property in material card (#117263) * update docs * * * typo * Revert "typo" This reverts commit 3e25d4be337b1a41d24b1a86136606d6551b30cf. * Update card.dart * Update card.dart * Update card.dart * Fix M3 `Drawer` default shape in RTL (#118185) * [M3] Add error state support for side property of CheckBox (#118386) * Add error state support for side property * lint fixes * lint fixes * Roll Plugins from 620a059d62b2 to 39197f17ca59 (6 revisions) (#118391) * 8c461cfde [gh_actions]: Bump ossf/scorecard-action from 2.0.6 to 2.1.2 (flutter/plugins#6882) * a119afd47 [in_app_pur]: Bump espresso-core from 3.4.0 to 3.5.1 in /packages/in_app_purchase/in_app_purchase_android/android (flutter/plugins#6924) * 12266846e Roll Flutter from 507062032fa4 to 7ddf42eae5ee (5 revisions) (flutter/plugins#6923) * 44098fe34 [shared_preferences] Switch to `shared_preferences_foundation` (flutter/plugins#6940) * 0dd166959 [tool] Replace `flutter format` (flutter/plugins#6946) * 39197f17c [gh_actions]: Bump actions/checkout from 3.1.0 to 3.3.0 (flutter/plugins#6935) * Move debug error message from failed pub to logger.printTrace (#118379) * Move debug error message from failed pub to logger.printTrace * Update test * [tool] Generate a binary version of the asset manifest (#117233) * initial * update asset_bundle_package_test * Update asset_bundle_test.dart * Update asset_bundle_package_fonts_test.dart * update pubspec checksum for smc dependency * flutter update-packages --force-upgrade * prefer += 1 over ++ Co-authored-by: Jonah Williams <jonahwilliams@google.com> * add regexp comment * rescope int list comparison function * update packages Co-authored-by: Jonah Williams <jonahwilliams@google.com> * IconButtonTheme should be overridden by the AppBar/AppBarTheme's iconTheme and actionsIconTheme (#118216) * reduce pub output from flutter create (#118285) * reduce pub output from flutter create * fix fake Pub implementations * fix tests * Update pub.dart * replace enum with simpler boolean * fix tests * Revert "fix tests" This reverts commit 8a3182d3b95d4f2bf337343cdb76e88c2f428ca8. * Revert "replace enum with simpler boolean" This reverts commit 445dbc443db4eb5ce284f76749f60e81208b8783. * go back to using an enum * roll packages (#118277) * [web] Update build to use generated JS runtime for Dart2Wasm. (#118359) * Roll Flutter Engine from 4a8d6866a1c0 to c01465a18f31 (9 revisions) (#118409) * 2d2c5e7eb Roll Dart SDK from 22fa50e09ee8 to 21f5de0ad596 (2 revisions) (flutter/engine#38796) * 24eb954da fix canvas drawLine bugs (flutter/engine#38753) * 2b024cbb6 [Impeller Scene] Change how property resolution works to fix Animation blending; add mutation log to nodes; enable backface culling; add vertex color contribution back to meshes (flutter/engine#38766) * 0192ea15e Roll Dart SDK from 21f5de0ad596 to 7879aa93da71 (1 revision) (flutter/engine#38804) * 5cd50f568 Roll Fuchsia Mac SDK from ao8fSjW8HrZSsu3yq... to gZ6xbsp2MRsoXfKgY... (flutter/engine#38806) * 4bf70c011 Roll Dart SDK from 7879aa93da71 to d7235947ff9b (1 revision) (flutter/engine#38808) * bb2d5e93a Roll Dart SDK from d7235947ff9b to edd406c07399 (2 revisions) (flutter/engine#38814) * 2a9fa7975 Revert "fix canvas drawLine bugs (#38753)" (flutter/engine#38815) * c01465a18 Add wasm_release build to linux_host_engine.json (flutter/engine#38755) * Add MSYS2 detection on Windows Terminal (#117612) As the results of "uname -s" command is like the below on MSYS2 on Windows Terminal, MSYS_NT-10.0-22621 This patch fixes the Flutter command working on this kind of systems. Signed-off-by: Deokgyu Yang <secugyu@gmail.com> Signed-off-by: Deokgyu Yang <secugyu@gmail.com> * Add documentation for drag/fling offset in WidgetController. (#118288) * Documentation for drag/fling offset * Fix typo * Fix typo 2 * Fix the docs_test * Fix the grammar * 688015782 fixed glfw example for arm64 (flutter/engine#38426) (#118413) * Use correct API docs link in create --sample help message (#118371) * Use correct API doc link in create --sample help message * Verify Flutter and Dart website links in tool help messages use https * Adjust test failure reasoning message * Roll Flutter Engine from 688015782762 to 35cfe9158648 (2 revisions) (#118415) * e9b7a2d38 [macOS] Do not block raster thread when shutting down (flutter/engine#38777) * 35cfe9158 Roll Fuchsia Mac SDK from gZ6xbsp2MRsoXfKgY... to nIPtQ59jG1pxyatOq... (flutter/engine#38819) * Fix tap/drag callbacks firing when TapAndDragGestureRecognizer has not won the arena (#118342) * Prevent drag and tap from accepting when a tap down exceeds the recognizers deadline but the recognizer has not won the arena * Add test * make analyzer happy Co-authored-by: Renzo Olivares <roliv@google.com> * 8aa26baa9 Roll Dart SDK from edd406c07399 to 20cca507d98b (1 revision) (flutter/engine#38823) (#118420) * add generated_plugins.cmake (#116581) Added files to the .gitignore that are generated on each "flutter pub get", so it's useless to ever commit these to a git repository. * Enable xcode cache cleanup for a few days. (#118419) This is to ensure the xcode caches get back to a normal state as they seem to have gotten into a bad state after updating the xcode version. Bug: https://github.com/flutter/flutter/issues/118324 Bug: https://github.com/flutter/flutter/issues/118327 Bug: https://github.com/flutter/flutter/issues/118328 * 99509a7e4 Correct FrameTimingRecorder's raster start time. (flutter/engine#38674) (#118425) * Roll Flutter Engine from 99509a7e4275 to f3f05368033b (2 revisions) (#118429) * 091c785a4 [windows] Use FML_DCHECK in place of C assert (flutter/engine#38826) * f3f053680 [windows] Eliminate unnecessary iostream imports (flutter/engine#38824) * Add `allowedButtonsFilter` to prevent Draggable from appearing with secondary click. (#111852) * DragTarget part 1. [WIP] Change GestureRecognizer. Sorry. [WIP] Move from GestureRecognizer to MultiDragGestureRecognizer. Make it a `Set<int>?` Get bitwise operations working. Fix test. Rename to allowedInputPointers. Convert into a builder. Improve code with default funciton. Refactor everything again. Rename to buttonEventFilter. Use static function. Fix analyzer. Fix private reference. Use // in private method. * Fix Renzo request. * Add `allowedButtonsFilter` everywhere. * Refactor monoDrag for multi pointer support. * Fix tests? * Change default to always true. * Fix PR comments. * Completely refactor long press. * Add forgotten class. * Revert "Completely refactor long press." This reverts commit 5038e8603e250e8c928b0f1754fb794b7b75738b. * Add default value to LongPress * Refactor doubleTap. * Relax double tap. * Write comment in LongPress. * Use template. * 15d59792e Roll Skia from dfb838747295 to 9e51c2c9e231 (26 revisions) (flutter/engine#38827) (#118432) * a62d25326 Roll Skia from dfb838747295 to cc983d28f3bf (27 revisions) (flutter/engine#38830) (#118435) * dfa0327f8 Roll Skia from cc983d28f3bf to fd54be29a3cc (3 revisions) (flutter/engine#38833) (#118436) * 07603c6d4 Roll Dart SDK from 20cca507d98b to 3d629d00a8d7 (2 revisions) (flutter/engine#38834) (#118439) * Fix copying/applying font fallback with package (#118393) * Add test to check that package prefix of font fallback is not duplicated * Fix duplicate package prefix of font family fallback * Add test to check that package prefix of font fallback is not duplicated * Fix duplicate package prefix of font family fallback * dec608917 Roll Fuchsia Mac SDK from nIPtQ59jG1pxyatOq... to 21nYb648VWbpxc36t... (flutter/engine#38839) (#118445) * 970889b87 Roll Skia from fd54be29a3cc to c72c7bf7e45b (3 revisions) (flutter/engine#38840) (#118448) * a512cebdc Roll Dart SDK from 3d629d00a8d7 to 645fd748e79e (1 revision) (flutter/engine#38841) (#118454) * Roll Plugins from 39197f17ca59 to 92a5367d58df (4 revisions) (#118457) * b89e4fc2d Roll Flutter from 7ddf42eae5ee to 0d91c0343bdc (58 revisions) (flutter/plugins#6948) * 86eda6992 [path_provider] Switch to Pigeon for macOS (flutter/plugins#6635) * be2e3de7a [shared_preferences_foundation] Add Swift runtime search paths for Objective-C apps (flutter/plugins#6952) * 92a5367d5 [tool] Fix false positives in update-exceprts (flutter/plugins#6950) * Added LinearBorder, an OutlinedBorder like BoxBorder (#116940) * Marks Mac_ios spell_check_test to be unflaky (#117743) * [Linux] Add a 'flutter run' console output test (#118279) * Add Linux support for the UI integration test project * Add Linux run console test * Add Info.plist from build directory as input path to Thin Binary build phase (#118209) * Add Info.plist from build directory as input path to Thin Binary build phase * fix directive ordering * migrate benchmark, integration, and example tests * [flutter_tools] re-enable web shader compilation (#118461) * [flutter_tools] re-enable web shader compilation * update test cases * Bump github/codeql-action from 2.1.37 to 2.1.38 (#118482) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.1.37 to 2.1.38. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](959cbb7472...515828d974
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * remove whitespace * add newline * newline fixes * newline fix * test fix * Update documentation about accent color (#116778) * e44a0de4c Roll Fuchsia Mac SDK from JLTTlcNPJeScjSO2B... to FeFYsNPy64-PEXPer... (flutter/engine#38558) (#117779) * Roll Plugins from e11cb245bb8e to 2d66f30e5825 (2 revisions) (#117781) * 417b37009 Roll Flutter from ae292cc4e5e4 to 17482fd425ee (28 revisions) (flutter/plugins#6889) * 2d66f30e5 [webview_flutter_web] Adds auto registration of the `WebViewPlatform` implementation (flutter/plugins#6886) * Roll Flutter Engine from 5713a216076f to 780082203ea9 (2 revisions) (#117797) * fd94b04b1 [Impeller Scene] Import skinned mesh vertex data (flutter/engine#38554) * 780082203 Roll Fuchsia Linux SDK from gnyHyot4AZp7HZgUI... to KCm_e3N4gosNuY4IW... (flutter/engine#38568) * Reland "Add support for double tap and drag for text selection #109573" (#117502) * Revert "Revert "Add support for double tap and drag for text selection (#109573)" (#117497)" This reverts commit 39fa0117a919bd401c4c8734c97ddb46fbc45cb7. * Allow TapAndDragGestureRecognizer to accept pointer events from any devices -- the TapGestureRecognizer it replaces was previously doing this Co-authored-by: Renzo Olivares <roliv@google.com> * roll packages (#117940) * roll packages (#118001) * [EMPTY] Commit to refresh the tree that is currently red (#118062) * Remove doc reference to the deprecated ui.FlutterWindow API (#118064) * Fix `flutter update-packages` regression by fixing parameters in "pub get" runner (#116687) * Make pub get runner respect printProgress and retry parameters * Fix typo * Add regression test * Improve test * Fix implementation and test * Test to fix flutter_drone tests * Revert test * Attempt #2 to fix flutter_drone tests * Revert attempt * Hack: Force printProgress to debug Windows tests * Use ProcessUtils.run to avoid dangling stdout and stderr * Update documentation * Clean up retry argument * [Impeller Scene] Add SceneC asset importing (#118157) * roll packages (#118117) * roll packages (#118272) * Align `flutter pub get/upgrade/add/remove/downgrade` (#117896) * Align `flutter pub get/upgrade/add/remove/downgrade` * Add final . to command description * Remove trailing whitespace * Don't print message that command is being run * Update expectations * Use relative path * Remove duplicated line * Improve function dartdoc * Bump github/codeql-action from 2.1.35 to 2.1.37 (#117104) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.1.35 to 2.1.37. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](b2a92eb56d...959cbb7472
) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Move debug error message from failed pub to logger.printTrace (#118379) * Move debug error message from failed pub to logger.printTrace * Update test * [tool] Generate a binary version of the asset manifest (#117233) * initial * update asset_bundle_package_test * Update asset_bundle_test.dart * Update asset_bundle_package_fonts_test.dart * update pubspec checksum for smc dependency * flutter update-packages --force-upgrade * prefer += 1 over ++ Co-authored-by: Jonah Williams <jonahwilliams@google.com> * add regexp comment * rescope int list comparison function * update packages Co-authored-by: Jonah Williams <jonahwilliams@google.com> * reduce pub output from flutter create (#118285) * reduce pub output from flutter create * fix fake Pub implementations * fix tests * Update pub.dart * replace enum with simpler boolean * fix tests * Revert "fix tests" This reverts commit 8a3182d3b95d4f2bf337343cdb76e88c2f428ca8. * Revert "replace enum with simpler boolean" This reverts commit 445dbc443db4eb5ce284f76749f60e81208b8783. * go back to using an enum * roll packages (#118277) * Fix tap/drag callbacks firing when TapAndDragGestureRecognizer has not won the arena (#118342) * Prevent drag and tap from accepting when a tap down exceeds the recognizers deadline but the recognizer has not won the arena * Add test * make analyzer happy Co-authored-by: Renzo Olivares <roliv@google.com> * Add `allowedButtonsFilter` to prevent Draggable from appearing with secondary click. (#111852) * DragTarget part 1. [WIP] Change GestureRecognizer. Sorry. [WIP] Move from GestureRecognizer to MultiDragGestureRecognizer. Make it a `Set<int>?` Get bitwise operations working. Fix test. Rename to allowedInputPointers. Convert into a builder. Improve code with default funciton. Refactor everything again. Rename to buttonEventFilter. Use static function. Fix analyzer. Fix private reference. Use // in private method. * Fix Renzo request. * Add `allowedButtonsFilter` everywhere. * Refactor monoDrag for multi pointer support. * Fix tests? * Change default to always true. * Fix PR comments. * Completely refactor long press. * Add forgotten class. * Revert "Completely refactor long press." This reverts commit 5038e8603e250e8c928b0f1754fb794b7b75738b. * Add default value to LongPress * Refactor doubleTap. * Relax double tap. * Write comment in LongPress. * Use template. * 15d59792e Roll Skia from dfb838747295 to 9e51c2c9e231 (26 revisions) (flutter/engine#38827) (#118432) * [flutter_tools] re-enable web shader compilation (#118461) * [flutter_tools] re-enable web shader compilation * update test cases * remove whitespace * fix rebase mess Signed-off-by: Morris Kurz <morriskurz@gmail.com> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Deokgyu Yang <secugyu@gmail.com> Co-authored-by: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> Co-authored-by: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Co-authored-by: Jesús S Guerrero <jesus_sguerrero@hotmail.com> Co-authored-by: Darren Austin <darrenaustin@google.com> Co-authored-by: Ahmed Ashour <asashour@yahoo.com> Co-authored-by: Michael Goderbauer <goderbauer@google.com> Co-authored-by: Greg Price <gnprice@gmail.com> Co-authored-by: CicadaCinema <52425971+CicadaCinema@users.noreply.github.com> Co-authored-by: Tae Hyung Kim <thkim1011@users.noreply.github.com> Co-authored-by: Renzo Olivares <rmolivares@renzo-olivares.dev> Co-authored-by: Renzo Olivares <roliv@google.com> Co-authored-by: Sam Rawlins <srawlins@google.com> Co-authored-by: Peixin Li <pageli328@gmail.com> Co-authored-by: Callum Moffat <smartercallum@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@google.com> Co-authored-by: Christopher Fujino <christopherfujino@gmail.com> Co-authored-by: Flutter GitHub Bot <fluttergithubbot@gmail.com> Co-authored-by: Camille Simon <43054281+camsim99@users.noreply.github.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Co-authored-by: Drew Roen <102626803+drewroengoogle@users.noreply.github.com> Co-authored-by: Jason Simmons <jason-simmons@users.noreply.github.com> Co-authored-by: Nehal Patel <nehalvpatel@users.noreply.github.com> Co-authored-by: gmackall <34871572+gmackall@users.noreply.github.com> Co-authored-by: Gray Mackall <mackall@google.com> Co-authored-by: Mohammed CHAHBOUN <69054810+M97Chahboun@users.noreply.github.com> Co-authored-by: Alex Wallen <wallenstephen@outlook.com> Co-authored-by: a-wallen <stephenwallen@google.com> Co-authored-by: Morris Kurz <morriskurz@gmail.com> Co-authored-by: Lucas.Xu <tsuiyuenhong@gmail.com> Co-authored-by: Jenn Magder <magder@google.com> Co-authored-by: Helin Shiah <helinx@google.com> Co-authored-by: Taha Tesser <tessertaha@gmail.com> Co-authored-by: Nicholas Shahan <nshahan@google.com> Co-authored-by: Yegor <yjbanov@google.com> Co-authored-by: Bruno Leroux <leroux_bruno@yahoo.fr> Co-authored-by: Brandon DeRosier <bdero@google.com> Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> Co-authored-by: Jonah Williams <jonahwilliams@google.com> Co-authored-by: Youchen Du <youchen.du@gmail.com> Co-authored-by: Sigurd Meldgaard <sigurdm@google.com> Co-authored-by: Rydmike <m.rydstrom@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Suhwan Cha <suhw4n@gmail.com> Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com> Co-authored-by: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Co-authored-by: joshualitt <joshualitt@google.com> Co-authored-by: Deokgyu Yang <secugyu@gmail.com> Co-authored-by: Peixin Li <peixinli@google.com> Co-authored-by: Parker Lougheed <parlough@gmail.com> Co-authored-by: Ivo Beckers <35917382+IvoB1987@users.noreply.github.com> Co-authored-by: godofredoc <godofredoc@google.com> Co-authored-by: Bernardo Ferrari <bernaferrari2@gmail.com> Co-authored-by: Dennis Kugelmann <kugelmann.dennis@gmail.com> Co-authored-by: Hans Muller <hans.muller@gmail.com> Co-authored-by: Victoria Ashworth <vashworth@google.com>
1942 lines
66 KiB
Dart
1942 lines
66 KiB
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:flutter/foundation.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
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() {
|
|
testWidgets('OutlinedButton, OutlinedButton.icon defaults', (WidgetTester tester) async {
|
|
const ColorScheme colorScheme = ColorScheme.light();
|
|
final ThemeData theme = ThemeData.from(colorScheme: colorScheme);
|
|
final bool material3 = theme.useMaterial3;
|
|
|
|
// Enabled OutlinedButton
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: Center(
|
|
child: OutlinedButton(
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder buttonMaterial = find.descendant(
|
|
of: find.byType(OutlinedButton),
|
|
matching: find.byType(Material),
|
|
);
|
|
|
|
Material material = tester.widget<Material>(buttonMaterial);
|
|
expect(material.animationDuration, const Duration(milliseconds: 200));
|
|
expect(material.borderOnForeground, true);
|
|
expect(material.borderRadius, null);
|
|
expect(material.clipBehavior, Clip.none);
|
|
expect(material.color, Colors.transparent);
|
|
expect(material.elevation, 0.0);
|
|
expect(material.shadowColor, material3 ? null : const Color(0xff000000));
|
|
|
|
expect(material.shape, material3
|
|
? StadiumBorder(side: BorderSide(color: colorScheme.outline))
|
|
: RoundedRectangleBorder(
|
|
side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)),
|
|
borderRadius: const BorderRadius.all(Radius.circular(4))
|
|
));
|
|
|
|
expect(material.textStyle!.color, colorScheme.primary);
|
|
expect(material.textStyle!.fontFamily, 'Roboto');
|
|
expect(material.textStyle!.fontSize, 14);
|
|
expect(material.textStyle!.fontWeight, FontWeight.w500);
|
|
expect(material.type, MaterialType.button);
|
|
|
|
final Align align = tester.firstWidget<Align>(find.ancestor(of: find.text('button'), matching: find.byType(Align)));
|
|
expect(align.alignment, Alignment.center);
|
|
|
|
final Offset center = tester.getCenter(find.byType(OutlinedButton));
|
|
final TestGesture gesture = await tester.startGesture(center);
|
|
await tester.pump(); // start the splash animation
|
|
await tester.pump(const Duration(milliseconds: 100)); // splash is underway
|
|
|
|
// Material 3 uses the InkSparkle which uses a shader, so we can't capture
|
|
// the effect with paint methods.
|
|
if (!material3) {
|
|
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
|
|
expect(inkFeatures, paints..circle(color: colorScheme.primary.withOpacity(0.12)));
|
|
}
|
|
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
// No change vs enabled and not pressed.
|
|
material = tester.widget<Material>(buttonMaterial);
|
|
expect(material.animationDuration, const Duration(milliseconds: 200));
|
|
expect(material.borderOnForeground, true);
|
|
expect(material.borderRadius, null);
|
|
expect(material.clipBehavior, Clip.none);
|
|
expect(material.color, Colors.transparent);
|
|
expect(material.elevation, 0.0);
|
|
expect(material.shadowColor, material3 ? null : const Color(0xff000000));
|
|
|
|
expect(material.shape, material3
|
|
? StadiumBorder(side: BorderSide(color: colorScheme.outline))
|
|
: RoundedRectangleBorder(
|
|
side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)),
|
|
borderRadius: const BorderRadius.all(Radius.circular(4))
|
|
));
|
|
|
|
expect(material.textStyle!.color, colorScheme.primary);
|
|
expect(material.textStyle!.fontFamily, 'Roboto');
|
|
expect(material.textStyle!.fontSize, 14);
|
|
expect(material.textStyle!.fontWeight, FontWeight.w500);
|
|
expect(material.type, MaterialType.button);
|
|
|
|
// Enabled OutlinedButton.icon
|
|
final Key iconButtonKey = UniqueKey();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: Center(
|
|
child: OutlinedButton.icon(
|
|
key: iconButtonKey,
|
|
onPressed: () { },
|
|
icon: const Icon(Icons.add),
|
|
label: const Text('label'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder iconButtonMaterial = find.descendant(
|
|
of: find.byKey(iconButtonKey),
|
|
matching: find.byType(Material),
|
|
);
|
|
|
|
material = tester.widget<Material>(iconButtonMaterial);
|
|
expect(material.animationDuration, const Duration(milliseconds: 200));
|
|
expect(material.borderOnForeground, true);
|
|
expect(material.borderRadius, null);
|
|
expect(material.clipBehavior, Clip.none);
|
|
expect(material.color, Colors.transparent);
|
|
expect(material.elevation, 0.0);
|
|
expect(material.shadowColor, material3 ? null : const Color(0xff000000));
|
|
|
|
expect(material.shape, material3
|
|
? StadiumBorder(side: BorderSide(color: colorScheme.outline))
|
|
: RoundedRectangleBorder(
|
|
side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)),
|
|
borderRadius: const BorderRadius.all(Radius.circular(4))
|
|
));
|
|
|
|
expect(material.textStyle!.color, colorScheme.primary);
|
|
expect(material.textStyle!.fontFamily, 'Roboto');
|
|
expect(material.textStyle!.fontSize, 14);
|
|
expect(material.textStyle!.fontWeight, FontWeight.w500);
|
|
expect(material.type, MaterialType.button);
|
|
|
|
// Disabled OutlinedButton
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: const Center(
|
|
child: OutlinedButton(
|
|
onPressed: null,
|
|
child: Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
material = tester.widget<Material>(buttonMaterial);
|
|
expect(material.animationDuration, const Duration(milliseconds: 200));
|
|
expect(material.borderOnForeground, true);
|
|
expect(material.borderRadius, null);
|
|
expect(material.clipBehavior, Clip.none);
|
|
expect(material.color, Colors.transparent);
|
|
expect(material.elevation, 0.0);
|
|
expect(material.shadowColor, material3 ? null : const Color(0xff000000));
|
|
|
|
expect(material.shape, material3
|
|
? StadiumBorder(side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)))
|
|
: RoundedRectangleBorder(
|
|
side: BorderSide(color: colorScheme.onSurface.withOpacity(0.12)),
|
|
borderRadius: const BorderRadius.all(Radius.circular(4))
|
|
));
|
|
|
|
expect(material.textStyle!.color, colorScheme.onSurface.withOpacity(0.38));
|
|
expect(material.textStyle!.fontFamily, 'Roboto');
|
|
expect(material.textStyle!.fontSize, 14);
|
|
expect(material.textStyle!.fontWeight, FontWeight.w500);
|
|
expect(material.type, MaterialType.button);
|
|
});
|
|
|
|
testWidgets('Does OutlinedButton work with hover', (WidgetTester tester) async {
|
|
const Color hoverColor = Color(0xff001122);
|
|
|
|
Color? getOverlayColor(Set<MaterialState> states) {
|
|
return states.contains(MaterialState.hovered) ? hoverColor : null;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
style: ButtonStyle(
|
|
overlayColor: MaterialStateProperty.resolveWith<Color?>(getOverlayColor),
|
|
),
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(tester.getCenter(find.byType(OutlinedButton)));
|
|
await tester.pumpAndSettle();
|
|
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
|
|
expect(inkFeatures, paints..rect(color: hoverColor));
|
|
});
|
|
|
|
testWidgets('Does OutlinedButton work with focus', (WidgetTester tester) async {
|
|
const Color focusColor = Color(0xff001122);
|
|
|
|
Color? getOverlayColor(Set<MaterialState> states) {
|
|
return states.contains(MaterialState.focused) ? focusColor : null;
|
|
}
|
|
|
|
final FocusNode focusNode = FocusNode(debugLabel: 'OutlinedButton Node');
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
style: ButtonStyle(
|
|
overlayColor: MaterialStateProperty.resolveWith<Color?>(getOverlayColor),
|
|
),
|
|
focusNode: focusNode,
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
);
|
|
|
|
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
|
|
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
|
|
expect(inkFeatures, paints..rect(color: focusColor));
|
|
});
|
|
|
|
testWidgets('Does OutlinedButton work with autofocus', (WidgetTester tester) async {
|
|
const Color focusColor = Color(0xff001122);
|
|
|
|
Color? getOverlayColor(Set<MaterialState> states) {
|
|
return states.contains(MaterialState.focused) ? focusColor : null;
|
|
}
|
|
|
|
final FocusNode focusNode = FocusNode(debugLabel: 'OutlinedButton Node');
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
autofocus: true,
|
|
style: ButtonStyle(
|
|
overlayColor: MaterialStateProperty.resolveWith<Color?>(getOverlayColor),
|
|
),
|
|
focusNode: focusNode,
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
);
|
|
|
|
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
|
await tester.pumpAndSettle();
|
|
|
|
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
|
|
expect(inkFeatures, paints..rect(color: focusColor));
|
|
});
|
|
|
|
testWidgets('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async {
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.from(colorScheme: const ColorScheme.light()),
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
onPressed: () {},
|
|
focusNode: focusNode,
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Default, not disabled.
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Focused.
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Hovered.
|
|
final Offset center = tester.getCenter(find.byType(OutlinedButton));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Highlighted (pressed).
|
|
await gesture.down(center);
|
|
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));
|
|
await gesture.removePointer();
|
|
},
|
|
skip: isBrowser, // https://github.com/flutter/flutter/issues/44115
|
|
);
|
|
|
|
testWidgets('OutlinedButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async {
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
Color getTextColor(Set<MaterialState> states) {
|
|
final Set<MaterialState> interactiveStates = <MaterialState>{
|
|
MaterialState.pressed,
|
|
MaterialState.hovered,
|
|
MaterialState.focused,
|
|
};
|
|
if (states.any(interactiveStates.contains)) {
|
|
return Colors.blue[900]!;
|
|
}
|
|
return Colors.blue[800]!;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.from(colorScheme: ColorScheme.fromSwatch()),
|
|
home: Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: Center(
|
|
child: OutlinedButtonTheme(
|
|
data: OutlinedButtonThemeData(
|
|
style: ButtonStyle(
|
|
foregroundColor: MaterialStateProperty.resolveWith<Color>(getTextColor),
|
|
),
|
|
),
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
return OutlinedButton(
|
|
onPressed: () {},
|
|
focusNode: focusNode,
|
|
child: const Text('OutlinedButton'),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Default, not disabled.
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Focused.
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Hovered.
|
|
final Offset center = tester.getCenter(find.byType(OutlinedButton));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
await expectLater(tester, meetsGuideline(textContrastGuideline));
|
|
|
|
// Highlighted (pressed).
|
|
await gesture.down(center);
|
|
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));
|
|
},
|
|
skip: isBrowser, // https://github.com/flutter/flutter/issues/44115
|
|
);
|
|
|
|
testWidgets('OutlinedButton uses stateful color for text color in different states', (WidgetTester tester) async {
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
const Color pressedColor = Color(0x00000001);
|
|
const Color hoverColor = Color(0x00000002);
|
|
const Color focusedColor = Color(0x00000003);
|
|
const Color defaultColor = Color(0x00000004);
|
|
|
|
Color getTextColor(Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return pressedColor;
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return hoverColor;
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return focusedColor;
|
|
}
|
|
return defaultColor;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
style: ButtonStyle(
|
|
foregroundColor: MaterialStateProperty.resolveWith<Color>(getTextColor),
|
|
),
|
|
onPressed: () {},
|
|
focusNode: focusNode,
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Color textColor() {
|
|
return tester.renderObject<RenderParagraph>(find.text('OutlinedButton')).text.style!.color!;
|
|
}
|
|
|
|
// Default, not disabled.
|
|
expect(textColor(), equals(defaultColor));
|
|
|
|
// Focused.
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
expect(textColor(), focusedColor);
|
|
|
|
// Hovered.
|
|
final Offset center = tester.getCenter(find.byType(OutlinedButton));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
expect(textColor(), hoverColor);
|
|
|
|
// Highlighted (pressed).
|
|
await gesture.down(center);
|
|
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);
|
|
});
|
|
|
|
testWidgets('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async {
|
|
final FocusNode focusNode = FocusNode();
|
|
final Key buttonKey = UniqueKey();
|
|
|
|
const Color pressedColor = Color(0x00000001);
|
|
const Color hoverColor = Color(0x00000002);
|
|
const Color focusedColor = Color(0x00000003);
|
|
const Color defaultColor = Color(0x00000004);
|
|
|
|
Color getIconColor(Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return pressedColor;
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return hoverColor;
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return focusedColor;
|
|
}
|
|
return defaultColor;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton.icon(
|
|
key: buttonKey,
|
|
style: ButtonStyle(
|
|
foregroundColor: MaterialStateProperty.resolveWith<Color>(getIconColor),
|
|
),
|
|
icon: const Icon(Icons.add),
|
|
label: const Text('OutlinedButton'),
|
|
onPressed: () {},
|
|
focusNode: focusNode,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
Color iconColor() => _iconStyle(tester, Icons.add).color!;
|
|
// Default, not disabled.
|
|
expect(iconColor(), equals(defaultColor));
|
|
|
|
// Focused.
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
expect(iconColor(), focusedColor);
|
|
|
|
// Hovered.
|
|
final Offset center = tester.getCenter(find.byKey(buttonKey));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
expect(iconColor(), hoverColor);
|
|
|
|
// Highlighted (pressed).
|
|
await gesture.down(center);
|
|
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);
|
|
});
|
|
|
|
testWidgets('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async {
|
|
final FocusNode focusNode = FocusNode();
|
|
|
|
const Color pressedColor = Color(0x00000001);
|
|
const Color hoverColor = Color(0x00000002);
|
|
const Color focusedColor = Color(0x00000003);
|
|
const Color defaultColor = Color(0x00000004);
|
|
|
|
BorderSide getBorderSide(Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return const BorderSide(color: pressedColor);
|
|
}
|
|
if (states.contains(MaterialState.hovered)) {
|
|
return const BorderSide(color: hoverColor);
|
|
}
|
|
if (states.contains(MaterialState.focused)) {
|
|
return const BorderSide(color: focusedColor);
|
|
}
|
|
return const BorderSide(color: defaultColor);
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
style: ButtonStyle(
|
|
side: MaterialStateProperty.resolveWith<BorderSide>(getBorderSide),
|
|
// Test assumes a rounded rect for the shape
|
|
shape: ButtonStyleButton.allOrNull(
|
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))
|
|
),
|
|
),
|
|
onPressed: () {},
|
|
focusNode: focusNode,
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder outlinedButton = find.byType(OutlinedButton);
|
|
|
|
// Default, not disabled.
|
|
expect(outlinedButton, paints..drrect(color: defaultColor));
|
|
|
|
// Focused.
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
expect(outlinedButton, paints..drrect(color: focusedColor));
|
|
|
|
// Hovered.
|
|
final Offset center = tester.getCenter(find.byType(OutlinedButton));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
expect(outlinedButton, paints..drrect(color: hoverColor));
|
|
|
|
// Highlighted (pressed).
|
|
await gesture.down(center);
|
|
await tester.pumpAndSettle();
|
|
expect(outlinedButton, paints..drrect(color: pressedColor));
|
|
});
|
|
|
|
testWidgets('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async {
|
|
|
|
bool wasPressed;
|
|
Finder outlinedButton;
|
|
|
|
Widget buildFrame({ VoidCallback? onPressed, VoidCallback? onLongPress }) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
onPressed: onPressed,
|
|
onLongPress: onLongPress,
|
|
child: const Text('button'),
|
|
),
|
|
);
|
|
}
|
|
|
|
// onPressed not null, onLongPress null.
|
|
wasPressed = false;
|
|
await tester.pumpWidget(
|
|
buildFrame(onPressed: () { wasPressed = true; }),
|
|
);
|
|
outlinedButton = find.byType(OutlinedButton);
|
|
expect(tester.widget<OutlinedButton>(outlinedButton).enabled, true);
|
|
await tester.tap(outlinedButton);
|
|
expect(wasPressed, true);
|
|
|
|
// onPressed null, onLongPress not null.
|
|
wasPressed = false;
|
|
await tester.pumpWidget(
|
|
buildFrame(onLongPress: () { wasPressed = true; }),
|
|
);
|
|
outlinedButton = find.byType(OutlinedButton);
|
|
expect(tester.widget<OutlinedButton>(outlinedButton).enabled, true);
|
|
await tester.longPress(outlinedButton);
|
|
expect(wasPressed, true);
|
|
|
|
// onPressed null, onLongPress null.
|
|
await tester.pumpWidget(
|
|
buildFrame(),
|
|
);
|
|
outlinedButton = find.byType(OutlinedButton);
|
|
expect(tester.widget<OutlinedButton>(outlinedButton).enabled, false);
|
|
});
|
|
|
|
testWidgets("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();
|
|
bool hovering = false;
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: SizedBox(
|
|
width: 100,
|
|
height: 100,
|
|
child: OutlinedButton(
|
|
autofocus: true,
|
|
onPressed: () {},
|
|
onLongPress: () {},
|
|
onHover: (bool value) { hovering = value; },
|
|
focusNode: focusNode,
|
|
child: SizedBox(key: childKey),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(focusNode.hasPrimaryFocus, isTrue);
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(tester.getCenter(find.byKey(childKey)));
|
|
await tester.pumpAndSettle();
|
|
expect(hovering, isTrue);
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: SizedBox(
|
|
width: 100,
|
|
height: 100,
|
|
child: OutlinedButton(
|
|
focusNode: focusNode,
|
|
onHover: (bool value) { hovering = value; },
|
|
onPressed: null,
|
|
child: SizedBox(key: childKey),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(focusNode.hasPrimaryFocus, isFalse);
|
|
});
|
|
|
|
testWidgets('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async {
|
|
int onHoverCount = 0;
|
|
late bool hover;
|
|
|
|
Widget buildFrame({ required bool enabled }) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 100,
|
|
height: 100,
|
|
child: OutlinedButton(
|
|
onPressed: enabled ? () { } : null,
|
|
onHover: (bool value) {
|
|
onHoverCount += 1;
|
|
hover = value;
|
|
},
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame(enabled: true));
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await gesture.addPointer();
|
|
|
|
await gesture.moveTo(tester.getCenter(find.byType(OutlinedButton)));
|
|
await tester.pumpAndSettle();
|
|
expect(onHoverCount, 1);
|
|
expect(hover, true);
|
|
|
|
await tester.pumpWidget(buildFrame(enabled: false));
|
|
await tester.pumpAndSettle();
|
|
await gesture.moveTo(Offset.zero);
|
|
// Even though the OutlinedButton has been disabled, the mouse-exit still
|
|
// causes onHover(false) to be called.
|
|
expect(onHoverCount, 2);
|
|
expect(hover, false);
|
|
|
|
await gesture.moveTo(tester.getCenter(find.byType(OutlinedButton)));
|
|
await tester.pumpAndSettle();
|
|
// We no longer see hover events because the OutlinedButton is disabled
|
|
// and it's no longer in the "hovering" state.
|
|
expect(onHoverCount, 2);
|
|
expect(hover, false);
|
|
|
|
await tester.pumpWidget(buildFrame(enabled: true));
|
|
await tester.pumpAndSettle();
|
|
// The OutlinedButton was enabled while it contained the mouse, however
|
|
// we do not call onHover() because it may call setState().
|
|
expect(onHoverCount, 2);
|
|
expect(hover, false);
|
|
|
|
await gesture.moveTo(tester.getCenter(find.byType(OutlinedButton)) - const Offset(1, 1));
|
|
await tester.pumpAndSettle();
|
|
// Moving the mouse a little within the OutlinedButton doesn't change anything.
|
|
expect(onHoverCount, 2);
|
|
expect(hover, false);
|
|
});
|
|
|
|
testWidgets('Can set OutlinedButton focus and Can set unFocus.', (WidgetTester tester) async {
|
|
final FocusNode node = FocusNode(debugLabel: 'OutlinedButton Focus');
|
|
bool gotFocus = false;
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
focusNode: node,
|
|
onFocusChange: (bool focused) => gotFocus = focused,
|
|
onPressed: () { },
|
|
child: const SizedBox(),
|
|
),
|
|
),
|
|
);
|
|
|
|
node.requestFocus();
|
|
|
|
await tester.pump();
|
|
|
|
expect(gotFocus, isTrue);
|
|
expect(node.hasFocus, isTrue);
|
|
|
|
node.unfocus();
|
|
await tester.pump();
|
|
|
|
expect(gotFocus, isFalse);
|
|
expect(node.hasFocus, isFalse);
|
|
});
|
|
|
|
testWidgets('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async {
|
|
final FocusNode node = FocusNode(debugLabel: 'OutlinedButton Focus');
|
|
bool gotFocus = false;
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
focusNode: node,
|
|
onFocusChange: (bool focused) => gotFocus = focused,
|
|
onPressed: null,
|
|
child: const SizedBox(),
|
|
),
|
|
),
|
|
);
|
|
|
|
node.requestFocus();
|
|
|
|
await tester.pump();
|
|
|
|
expect(gotFocus, isFalse);
|
|
expect(node.hasFocus, isFalse);
|
|
});
|
|
|
|
testWidgets("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async {
|
|
Widget buildFrame(VoidCallback? onPressed) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Theme(
|
|
data: ThemeData(),
|
|
child: Center(
|
|
child: OutlinedButton(onPressed: onPressed, child: const Text('button')),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await tester.pumpWidget(buildFrame(() {}));
|
|
await tester.press(find.byType(OutlinedButton));
|
|
await tester.pumpAndSettle();
|
|
await tester.pumpWidget(buildFrame(null));
|
|
await tester.pumpAndSettle();
|
|
});
|
|
|
|
testWidgets('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);
|
|
const BorderSide pressedBorderSide = BorderSide(color: Color(0xFF0000FF), width: 5);
|
|
|
|
Widget buildFrame({ VoidCallback? onPressed }) {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Theme(
|
|
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, textTheme: Typography.englishLike2014),
|
|
child: Container(
|
|
alignment: Alignment.topLeft,
|
|
child: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
shape: const RoundedRectangleBorder(), // default border radius is 0
|
|
backgroundColor: fillColor,
|
|
minimumSize: const Size(64, 36),
|
|
).copyWith(
|
|
side: MaterialStateProperty.resolveWith<BorderSide>((Set<MaterialState> states) {
|
|
if (states.contains(MaterialState.disabled)) {
|
|
return disabledBorderSide;
|
|
}
|
|
if (states.contains(MaterialState.pressed)) {
|
|
return pressedBorderSide;
|
|
}
|
|
return enabledBorderSide;
|
|
}),
|
|
),
|
|
clipBehavior: Clip.antiAlias,
|
|
onPressed: onPressed,
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
final Finder outlinedButton = find.byType(OutlinedButton);
|
|
|
|
BorderSide getBorderSide() {
|
|
final OutlinedBorder border = tester.widget<Material>(
|
|
find.descendant(of: outlinedButton, matching: find.byType(Material)),
|
|
).shape! as OutlinedBorder;
|
|
return border.side;
|
|
}
|
|
|
|
// Pump a button with a null onPressed callback to make it disabled.
|
|
await tester.pumpWidget(
|
|
buildFrame(),
|
|
);
|
|
|
|
// Expect that the button is disabled and painted with the disabled border color.
|
|
expect(tester.widget<OutlinedButton>(outlinedButton).enabled, false);
|
|
expect(getBorderSide(), disabledBorderSide);
|
|
|
|
// Pump a new button with a no-op onPressed callback to make it enabled.
|
|
await tester.pumpWidget(
|
|
buildFrame(onPressed: () {}),
|
|
);
|
|
|
|
// Wait for the border color to change from disabled to enabled.
|
|
await tester.pumpAndSettle();
|
|
expect(getBorderSide(), enabledBorderSide);
|
|
|
|
final Offset center = tester.getCenter(outlinedButton);
|
|
final TestGesture gesture = await tester.startGesture(center);
|
|
await tester.pump(); // start gesture
|
|
|
|
// Wait for the border's color to change to pressed
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
expect(getBorderSide(), pressedBorderSide);
|
|
|
|
// Tap gesture completes, button returns to its initial configuration.
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
expect(getBorderSide(), enabledBorderSide);
|
|
});
|
|
|
|
testWidgets('OutlinedButton has no clip by default', (WidgetTester tester) async {
|
|
final GlobalKey buttonKey = GlobalKey();
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
key: buttonKey,
|
|
onPressed: () {},
|
|
child: const Text('ABC'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.renderObject(find.byKey(buttonKey)),
|
|
paintsExactlyCountTimes(#clipPath, 0),
|
|
);
|
|
});
|
|
|
|
|
|
testWidgets('OutlinedButton contributes semantics', (WidgetTester tester) async {
|
|
final SemanticsTester semantics = SemanticsTester(tester);
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
style: const ButtonStyle(
|
|
// Specifying minimumSize to mimic the original minimumSize for
|
|
// RaisedButton so that the corresponding button size matches
|
|
// the original version of this test.
|
|
minimumSize: MaterialStatePropertyAll<Size>(Size(88, 36)),
|
|
),
|
|
onPressed: () {},
|
|
child: const Text('ABC'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(semantics, hasSemantics(
|
|
TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics.rootChild(
|
|
actions: <SemanticsAction>[
|
|
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>[
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
),
|
|
],
|
|
),
|
|
ignoreId: true,
|
|
));
|
|
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('OutlinedButton scales textScaleFactor', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
Theme(
|
|
// Force Material 2 typography.
|
|
data: ThemeData(textTheme: Typography.englishLike2014),
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MediaQuery(
|
|
data: const MediaQueryData(),
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
style: const ButtonStyle(
|
|
// Specifying minimumSize to mimic the original minimumSize for
|
|
// RaisedButton so that the corresponding button size matches
|
|
// the original version of this test.
|
|
minimumSize: MaterialStatePropertyAll<Size>(Size(88, 36)),
|
|
),
|
|
onPressed: () {},
|
|
child: const Text('ABC'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getSize(find.byType(OutlinedButton)), equals(const Size(88.0, 48.0)));
|
|
expect(tester.getSize(find.byType(Text)), equals(const Size(42.0, 14.0)));
|
|
|
|
// textScaleFactor expands text, but not button.
|
|
await tester.pumpWidget(
|
|
Theme(
|
|
// Force Material 2 typography.
|
|
data: ThemeData(textTheme: Typography.englishLike2014),
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MediaQuery(
|
|
data: const MediaQueryData(textScaleFactor: 1.3),
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
style: const ButtonStyle(
|
|
// Specifying minimumSize to mimic the original minimumSize for
|
|
// RaisedButton so that the corresponding button size matches
|
|
// the original version of this test.
|
|
minimumSize: MaterialStatePropertyAll<Size>(Size(88, 36)),
|
|
),
|
|
onPressed: () {},
|
|
child: const Text('ABC'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getSize(find.byType(OutlinedButton)), equals(const Size(88.0, 48.0)));
|
|
// Scaled text rendering is different on Linux and Mac by one pixel.
|
|
// TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357
|
|
expect(tester.getSize(find.byType(Text)).width, isIn(<double>[54.0, 55.0]));
|
|
expect(tester.getSize(find.byType(Text)).height, isIn(<double>[18.0, 19.0]));
|
|
|
|
// Set text scale large enough to expand text and button.
|
|
await tester.pumpWidget(
|
|
Theme(
|
|
// Force Material 2 typography.
|
|
data: ThemeData(textTheme: Typography.englishLike2014),
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MediaQuery(
|
|
data: const MediaQueryData(textScaleFactor: 3.0),
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
onPressed: () {},
|
|
child: const Text('ABC'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// Scaled text rendering is different on Linux and Mac by one pixel.
|
|
// TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357
|
|
expect(tester.getSize(find.byType(OutlinedButton)).width, isIn(<double>[133.0, 134.0]));
|
|
expect(tester.getSize(find.byType(OutlinedButton)).height, equals(48.0));
|
|
expect(tester.getSize(find.byType(Text)).width, isIn(<double>[126.0, 127.0]));
|
|
expect(tester.getSize(find.byType(Text)).height, equals(42.0));
|
|
});
|
|
|
|
testWidgets('OutlinedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async {
|
|
bool didPressButton = false;
|
|
bool didLongPressButton = false;
|
|
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: OutlinedButton(
|
|
onPressed: () {
|
|
didPressButton = true;
|
|
},
|
|
onLongPress: () {
|
|
didLongPressButton = true;
|
|
},
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Finder outlinedButton = find.byType(OutlinedButton);
|
|
expect(tester.widget<OutlinedButton>(outlinedButton).enabled, true);
|
|
|
|
expect(didPressButton, isFalse);
|
|
await tester.tap(outlinedButton);
|
|
expect(didPressButton, isTrue);
|
|
|
|
expect(didLongPressButton, isFalse);
|
|
await tester.longPress(outlinedButton);
|
|
expect(didLongPressButton, isTrue);
|
|
});
|
|
|
|
testWidgets('OutlinedButton responds to density changes.', (WidgetTester tester) async {
|
|
const Key key = Key('test');
|
|
const Key childKey = Key('test child');
|
|
|
|
Future<void> buildTest(VisualDensity visualDensity, {bool useText = false}) async {
|
|
return tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(textTheme: Typography.englishLike2014),
|
|
home: Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Center(
|
|
child: OutlinedButton(
|
|
style: ButtonStyle(
|
|
visualDensity: visualDensity,
|
|
minimumSize: ButtonStyleButton.allOrNull(const Size(64, 36)),
|
|
),
|
|
key: key,
|
|
onPressed: () {},
|
|
child: useText
|
|
? const Text('Text', key: childKey)
|
|
: Container(key: childKey, width: 100, height: 100, color: const Color(0xffff0000)),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
await buildTest(VisualDensity.standard);
|
|
final RenderBox box = tester.renderObject(find.byKey(key));
|
|
Rect childRect = tester.getRect(find.byKey(childKey));
|
|
await tester.pumpAndSettle();
|
|
expect(box.size, equals(const Size(132, 100)));
|
|
expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350)));
|
|
|
|
await buildTest(const VisualDensity(horizontal: 3.0, vertical: 3.0));
|
|
await tester.pumpAndSettle();
|
|
childRect = tester.getRect(find.byKey(childKey));
|
|
expect(box.size, equals(const Size(156, 124)));
|
|
expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350)));
|
|
|
|
await buildTest(const VisualDensity(horizontal: -3.0, vertical: -3.0));
|
|
await tester.pumpAndSettle();
|
|
childRect = tester.getRect(find.byKey(childKey));
|
|
expect(box.size, equals(const Size(132, 100)));
|
|
expect(childRect, equals(const Rect.fromLTRB(350, 250, 450, 350)));
|
|
|
|
await buildTest(VisualDensity.standard, useText: true);
|
|
await tester.pumpAndSettle();
|
|
childRect = tester.getRect(find.byKey(childKey));
|
|
expect(box.size, equals(const Size(88, 48)));
|
|
expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0)));
|
|
|
|
await buildTest(const VisualDensity(horizontal: 3.0, vertical: 3.0), useText: true);
|
|
await tester.pumpAndSettle();
|
|
childRect = tester.getRect(find.byKey(childKey));
|
|
expect(box.size, equals(const Size(112, 60)));
|
|
expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0)));
|
|
|
|
await buildTest(const VisualDensity(horizontal: -3.0, vertical: -3.0), useText: true);
|
|
await tester.pumpAndSettle();
|
|
childRect = tester.getRect(find.byKey(childKey));
|
|
expect(box.size, equals(const Size(88, 36)));
|
|
expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0)));
|
|
});
|
|
|
|
group('Default OutlinedButton padding for textScaleFactor, textDirection', () {
|
|
const ValueKey<String> buttonKey = ValueKey<String>('button');
|
|
const ValueKey<String> labelKey = ValueKey<String>('label');
|
|
const ValueKey<String> iconKey = ValueKey<String>('icon');
|
|
|
|
const List<double> textScaleFactorOptions = <double>[0.5, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0];
|
|
const List<TextDirection> textDirectionOptions = <TextDirection>[TextDirection.ltr, TextDirection.rtl];
|
|
const List<Widget?> iconOptions = <Widget?>[null, Icon(Icons.add, size: 18, key: iconKey)];
|
|
|
|
// Expected values for each textScaleFactor.
|
|
final Map<double, double> paddingVertical = <double, double>{
|
|
0.5: 0,
|
|
1: 0,
|
|
1.25: 0,
|
|
1.5: 0,
|
|
2: 0,
|
|
2.5: 0,
|
|
3: 0,
|
|
4: 0,
|
|
};
|
|
final Map<double, double> paddingWithIconGap = <double, double>{
|
|
0.5: 8,
|
|
1: 8,
|
|
1.25: 7,
|
|
1.5: 6,
|
|
2: 4,
|
|
2.5: 4,
|
|
3: 4,
|
|
4: 4,
|
|
};
|
|
final Map<double, double> paddingHorizontal = <double, double>{
|
|
0.5: 16,
|
|
1: 16,
|
|
1.25: 14,
|
|
1.5: 12,
|
|
2: 8,
|
|
2.5: 6,
|
|
3: 4,
|
|
4: 4,
|
|
};
|
|
|
|
Rect globalBounds(RenderBox renderBox) {
|
|
final Offset topLeft = renderBox.localToGlobal(Offset.zero);
|
|
return topLeft & renderBox.size;
|
|
}
|
|
|
|
/// Computes the padding between two [Rect]s, one inside the other.
|
|
EdgeInsets paddingBetween({ required Rect parent, required Rect child }) {
|
|
assert (parent.intersect(child) == child);
|
|
return EdgeInsets.fromLTRB(
|
|
child.left - parent.left,
|
|
child.top - parent.top,
|
|
parent.right - child.right,
|
|
parent.bottom - child.bottom,
|
|
);
|
|
}
|
|
|
|
for (final double textScaleFactor in textScaleFactorOptions) {
|
|
for (final TextDirection textDirection in textDirectionOptions) {
|
|
for (final Widget? icon in iconOptions) {
|
|
final String testName = <String>[
|
|
'OutlinedButton, text scale $textScaleFactor',
|
|
if (icon != null)
|
|
'with icon',
|
|
if (textDirection == TextDirection.rtl)
|
|
'RTL',
|
|
].join(', ');
|
|
testWidgets(testName, (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(
|
|
colorScheme: const ColorScheme.light(),
|
|
// Force Material 2 defaults for the typography and size
|
|
// default values as the test was designed against these settings.
|
|
textTheme: Typography.englishLike2014,
|
|
outlinedButtonTheme: OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(minimumSize: const Size(64, 36)),
|
|
),
|
|
),
|
|
home: Builder(
|
|
builder: (BuildContext context) {
|
|
return MediaQuery(
|
|
data: MediaQuery.of(context).copyWith(
|
|
textScaleFactor: textScaleFactor,
|
|
),
|
|
child: Directionality(
|
|
textDirection: textDirection,
|
|
child: Scaffold(
|
|
body: Center(
|
|
child: icon == null
|
|
? OutlinedButton(
|
|
key: buttonKey,
|
|
onPressed: () {},
|
|
child: const Text('button', key: labelKey),
|
|
)
|
|
: OutlinedButton.icon(
|
|
key: buttonKey,
|
|
onPressed: () {},
|
|
icon: icon,
|
|
label: const Text('button', key: labelKey),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
|
|
final Element paddingElement = tester.element(
|
|
find.descendant(
|
|
of: find.byKey(buttonKey),
|
|
matching: find.byType(Padding),
|
|
),
|
|
);
|
|
expect(Directionality.of(paddingElement), textDirection);
|
|
final Padding paddingWidget = paddingElement.widget as Padding;
|
|
|
|
// Compute expected padding, and check.
|
|
|
|
final double expectedPaddingTop = paddingVertical[textScaleFactor]!;
|
|
final double expectedPaddingBottom = paddingVertical[textScaleFactor]!;
|
|
final double expectedPaddingStart = paddingHorizontal[textScaleFactor]!;
|
|
final double expectedPaddingEnd = expectedPaddingStart;
|
|
|
|
final EdgeInsets expectedPadding = EdgeInsetsDirectional.fromSTEB(
|
|
expectedPaddingStart,
|
|
expectedPaddingTop,
|
|
expectedPaddingEnd,
|
|
expectedPaddingBottom,
|
|
).resolve(textDirection);
|
|
|
|
expect(paddingWidget.padding.resolve(textDirection), expectedPadding);
|
|
|
|
// Measure padding in terms of the difference between the button and its label child
|
|
// and check that.
|
|
|
|
final RenderBox labelRenderBox = tester.renderObject<RenderBox>(find.byKey(labelKey));
|
|
final Rect labelBounds = globalBounds(labelRenderBox);
|
|
final RenderBox? iconRenderBox = icon == null ? null : tester.renderObject<RenderBox>(find.byKey(iconKey));
|
|
final Rect? iconBounds = icon == null ? null : globalBounds(iconRenderBox!);
|
|
final Rect childBounds = icon == null ? labelBounds : labelBounds.expandToInclude(iconBounds!);
|
|
|
|
// We measure the `InkResponse` descendant of the button
|
|
// element, because the button has a larger `RenderBox`
|
|
// which accommodates the minimum tap target with a height
|
|
// of 48.
|
|
final RenderBox buttonRenderBox = tester.renderObject<RenderBox>(
|
|
find.descendant(
|
|
of: find.byKey(buttonKey),
|
|
matching: find.byWidgetPredicate(
|
|
(Widget widget) => widget is InkResponse,
|
|
),
|
|
),
|
|
);
|
|
final Rect buttonBounds = globalBounds(buttonRenderBox);
|
|
final EdgeInsets visuallyMeasuredPadding = paddingBetween(
|
|
parent: buttonBounds,
|
|
child: childBounds,
|
|
);
|
|
|
|
// Since there is a requirement of a minimum width of 64
|
|
// and a minimum height of 36 on material buttons, the visual
|
|
// padding of smaller buttons may not match their settings.
|
|
// Therefore, we only test buttons that are large enough.
|
|
if (buttonBounds.width > 64) {
|
|
expect(
|
|
visuallyMeasuredPadding.left,
|
|
expectedPadding.left,
|
|
);
|
|
expect(
|
|
visuallyMeasuredPadding.right,
|
|
expectedPadding.right,
|
|
);
|
|
}
|
|
|
|
if (buttonBounds.height > 36) {
|
|
expect(
|
|
visuallyMeasuredPadding.top,
|
|
expectedPadding.top,
|
|
);
|
|
expect(
|
|
visuallyMeasuredPadding.bottom,
|
|
expectedPadding.bottom,
|
|
);
|
|
}
|
|
|
|
// Check the gap between the icon and the label
|
|
if (icon != null) {
|
|
final double gapWidth = textDirection == TextDirection.ltr
|
|
? labelBounds.left - iconBounds!.right
|
|
: iconBounds!.left - labelBounds.right;
|
|
expect(gapWidth, paddingWithIconGap[textScaleFactor]);
|
|
}
|
|
|
|
// Check the text's height - should be consistent with the textScaleFactor.
|
|
final RenderBox textRenderObject = tester.renderObject<RenderBox>(
|
|
find.descendant(
|
|
of: find.byKey(labelKey),
|
|
matching: find.byElementPredicate(
|
|
(Element element) => element.widget is RichText,
|
|
),
|
|
),
|
|
);
|
|
final double textHeight = textRenderObject.paintBounds.size.height;
|
|
final double expectedTextHeight = 14 * textScaleFactor;
|
|
expect(textHeight, moreOrLessEquals(expectedTextHeight, epsilon: 0.5));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
testWidgets('Override OutlinedButton default padding', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.from(colorScheme: const ColorScheme.light()),
|
|
home: Builder(
|
|
builder: (BuildContext context) {
|
|
return MediaQuery(
|
|
data: MediaQuery.of(context).copyWith(
|
|
textScaleFactor: 2,
|
|
),
|
|
child: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(padding: const EdgeInsets.all(22)),
|
|
onPressed: () {},
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
|
|
final Padding paddingWidget = tester.widget<Padding>(
|
|
find.descendant(
|
|
of: find.byType(OutlinedButton),
|
|
matching: find.byType(Padding),
|
|
),
|
|
);
|
|
expect(paddingWidget.padding, const EdgeInsets.all(22));
|
|
});
|
|
|
|
testWidgets('M3 OutlinedButton has correct padding', (WidgetTester tester) async {
|
|
final Key key = UniqueKey();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true),
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
key: key,
|
|
onPressed: () {},
|
|
child: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Padding paddingWidget = tester.widget<Padding>(
|
|
find.descendant(
|
|
of: find.byKey(key),
|
|
matching: find.byType(Padding),
|
|
),
|
|
);
|
|
expect(paddingWidget.padding, const EdgeInsets.symmetric(horizontal: 24));
|
|
});
|
|
|
|
testWidgets('M3 OutlinedButton.icon has correct padding', (WidgetTester tester) async {
|
|
final Key key = UniqueKey();
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true),
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton.icon(
|
|
key: key,
|
|
icon: const Icon(Icons.favorite),
|
|
onPressed: () {},
|
|
label: const Text('OutlinedButton'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Padding paddingWidget = tester.widget<Padding>(
|
|
find.descendant(
|
|
of: find.byKey(key),
|
|
matching: find.byType(Padding),
|
|
),
|
|
);
|
|
expect(paddingWidget.padding, const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 24.0, 0.0));
|
|
});
|
|
|
|
testWidgets('Fixed size OutlinedButtons', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(fixedSize: const Size(100, 100)),
|
|
onPressed: () {},
|
|
child: const Text('100x100'),
|
|
),
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(fixedSize: const Size.fromWidth(200)),
|
|
onPressed: () {},
|
|
child: const Text('200xh'),
|
|
),
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(fixedSize: const Size.fromHeight(200)),
|
|
onPressed: () {},
|
|
child: const Text('wx200'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getSize(find.widgetWithText(OutlinedButton, '100x100')), const Size(100, 100));
|
|
expect(tester.getSize(find.widgetWithText(OutlinedButton, '200xh')).width, 200);
|
|
expect(tester.getSize(find.widgetWithText(OutlinedButton, 'wx200')).height, 200);
|
|
});
|
|
|
|
testWidgets('OutlinedButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async {
|
|
Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
splashFactory: splashFactory,
|
|
),
|
|
onPressed: () { },
|
|
child: const Text('test'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// NoSplash.splashFactory, no splash circles drawn
|
|
await tester.pumpWidget(buildFrame(splashFactory: NoSplash.splashFactory));
|
|
{
|
|
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
|
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
expect(material, paintsExactlyCountTimes(#drawCircle, 0));
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
// InkRipple.splashFactory, one splash circle drawn.
|
|
await tester.pumpWidget(buildFrame(splashFactory: InkRipple.splashFactory));
|
|
{
|
|
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('test')));
|
|
final MaterialInkController material = Material.of(tester.element(find.text('test')));
|
|
await tester.pump(const Duration(milliseconds: 200));
|
|
expect(material, paintsExactlyCountTimes(#drawCircle, 1));
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
}
|
|
});
|
|
|
|
testWidgets('OutlinedButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async {
|
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: Center(
|
|
child: OutlinedButton(
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final InkWell buttonInkWell = tester.widget<InkWell>(find.descendant(
|
|
of: find.byType(OutlinedButton),
|
|
matching: find.byType(InkWell),
|
|
));
|
|
|
|
if (debugDefaultTargetPlatformOverride! == TargetPlatform.android && !kIsWeb) {
|
|
expect(buttonInkWell.splashFactory, equals(InkSparkle.splashFactory));
|
|
} else {
|
|
expect(buttonInkWell.splashFactory, equals(InkRipple.splashFactory));
|
|
}
|
|
}, variant: TargetPlatformVariant.all());
|
|
|
|
testWidgets('OutlinedButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async {
|
|
final ThemeData theme = ThemeData(useMaterial3: false);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: theme,
|
|
home: Center(
|
|
child: OutlinedButton(
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final InkWell buttonInkWell = tester.widget<InkWell>(find.descendant(
|
|
of: find.byType(OutlinedButton),
|
|
matching: find.byType(InkWell),
|
|
));
|
|
expect(buttonInkWell.splashFactory, equals(InkRipple.splashFactory));
|
|
}, variant: TargetPlatformVariant.all());
|
|
|
|
testWidgets('OutlinedButton.icon does not overflow', (WidgetTester tester) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/77815
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: SizedBox(
|
|
width: 200,
|
|
child: OutlinedButton.icon(
|
|
onPressed: () {},
|
|
icon: const Icon(Icons.add),
|
|
label: const Text( // Much wider than 200
|
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a euismod nibh. Morbi laoreet purus.',
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
expect(tester.takeException(), null);
|
|
});
|
|
|
|
testWidgets('OultinedButton.icon icon,label layout', (WidgetTester tester) async {
|
|
final Key buttonKey = UniqueKey();
|
|
final Key iconKey = UniqueKey();
|
|
final Key labelKey = UniqueKey();
|
|
final ButtonStyle style = OutlinedButton.styleFrom(
|
|
padding: EdgeInsets.zero,
|
|
visualDensity: VisualDensity.standard, // dx=0, dy=0
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: SizedBox(
|
|
width: 200,
|
|
child: OutlinedButton.icon(
|
|
key: buttonKey,
|
|
style: style,
|
|
onPressed: () {},
|
|
icon: SizedBox(key: iconKey, width: 50, height: 100),
|
|
label: SizedBox(key: labelKey, width: 50, height: 100),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// The button's label and icon are separated by a gap of 8:
|
|
// 46 [icon 50] 8 [label 50] 46
|
|
// The overall button width is 200. So:
|
|
// icon.x = 46
|
|
// label.x = 46 + 50 + 8 = 104
|
|
|
|
expect(tester.getRect(find.byKey(buttonKey)), const Rect.fromLTRB(0.0, 0.0, 200.0, 100.0));
|
|
expect(tester.getRect(find.byKey(iconKey)), const Rect.fromLTRB(46.0, 0.0, 96.0, 100.0));
|
|
expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0));
|
|
});
|
|
|
|
testWidgets('OutlinedButton maximumSize', (WidgetTester tester) async {
|
|
final Key key0 = UniqueKey();
|
|
final Key key1 = UniqueKey();
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
theme: ThemeData(textTheme: Typography.englishLike2014),
|
|
home: Scaffold(
|
|
body: Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
OutlinedButton(
|
|
key: key0,
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size(24, 36),
|
|
maximumSize: const Size.fromWidth(64),
|
|
),
|
|
onPressed: () { },
|
|
child: const Text('A B C D E F G H I J K L M N O P'),
|
|
),
|
|
OutlinedButton.icon(
|
|
key: key1,
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size(24, 36),
|
|
maximumSize: const Size.fromWidth(104),
|
|
),
|
|
onPressed: () {},
|
|
icon: Container(color: Colors.red, width: 32, height: 32),
|
|
label: const Text('A B C D E F G H I J K L M N O P'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getSize(find.byKey(key0)), const Size(64.0, 224.0));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0));
|
|
});
|
|
|
|
testWidgets('Fixed size OutlinedButton, same as minimumSize == maximumSize', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: <Widget>[
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(fixedSize: const Size(200, 200)),
|
|
onPressed: () { },
|
|
child: const Text('200x200'),
|
|
),
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size(200, 200),
|
|
maximumSize: const Size(200, 200),
|
|
),
|
|
onPressed: () { },
|
|
child: const Text('200,200'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(tester.getSize(find.widgetWithText(OutlinedButton, '200x200')), const Size(200, 200));
|
|
expect(tester.getSize(find.widgetWithText(OutlinedButton, '200,200')), const Size(200, 200));
|
|
});
|
|
|
|
testWidgets('OutlinedButton changes mouse cursor when hovered', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
enabledMouseCursor: SystemMouseCursors.text,
|
|
disabledMouseCursor: SystemMouseCursors.grab,
|
|
),
|
|
onPressed: () {},
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
|
|
await gesture.addPointer(location: Offset.zero);
|
|
|
|
await tester.pump();
|
|
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
|
|
|
|
// Test cursor when disabled
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
enabledMouseCursor: SystemMouseCursors.text,
|
|
disabledMouseCursor: SystemMouseCursors.grab,
|
|
),
|
|
onPressed: null,
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grab);
|
|
|
|
// Test default cursor
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: OutlinedButton(
|
|
onPressed: () {},
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
|
|
|
|
// Test default cursor when disabled
|
|
await tester.pumpWidget(
|
|
const Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: OutlinedButton(
|
|
onPressed: null,
|
|
child: Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
|
|
});
|
|
|
|
testWidgets('OutlinedButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
body: OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: Colors.white,
|
|
backgroundColor: Colors.purple,
|
|
),
|
|
onPressed: () {},
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final Material material = tester.widget<Material>(find.descendant(
|
|
of: find.byType(OutlinedButton),
|
|
matching: find.byType(Material),
|
|
));
|
|
expect(material.color, Colors.purple);
|
|
expect(material.textStyle!.color, Colors.white);
|
|
});
|
|
|
|
Future<void> testStatesController(Widget? icon, WidgetTester tester) async {
|
|
int count = 0;
|
|
void valueChanged() {
|
|
count += 1;
|
|
}
|
|
final MaterialStatesController controller = MaterialStatesController();
|
|
controller.addListener(valueChanged);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Center(
|
|
child: icon == null
|
|
? OutlinedButton(
|
|
statesController: controller,
|
|
onPressed: () { },
|
|
child: const Text('button'),
|
|
)
|
|
: OutlinedButton.icon(
|
|
statesController: controller,
|
|
onPressed: () { },
|
|
icon: icon,
|
|
label: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(controller.value, <MaterialState>{});
|
|
expect(count, 0);
|
|
|
|
final Offset center = tester.getCenter(find.byType(Text));
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
);
|
|
await gesture.addPointer();
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered});
|
|
expect(count, 1);
|
|
|
|
await gesture.moveTo(Offset.zero);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{});
|
|
expect(count, 2);
|
|
|
|
await gesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered});
|
|
expect(count, 3);
|
|
|
|
await gesture.down(center);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered, MaterialState.pressed});
|
|
expect(count, 4);
|
|
|
|
await gesture.up();
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered});
|
|
expect(count, 5);
|
|
|
|
await gesture.moveTo(Offset.zero);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(controller.value, <MaterialState>{});
|
|
expect(count, 6);
|
|
|
|
await gesture.down(center);
|
|
await tester.pumpAndSettle();
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered, MaterialState.pressed});
|
|
expect(count, 8); // adds hovered and pressed - two changes
|
|
|
|
// If the button is rebuilt disabled, then the pressed state is
|
|
// removed.
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Center(
|
|
child: icon == null
|
|
? OutlinedButton(
|
|
statesController: controller,
|
|
onPressed: null,
|
|
child: const Text('button'),
|
|
)
|
|
: OutlinedButton.icon(
|
|
statesController: controller,
|
|
onPressed: null,
|
|
icon: icon,
|
|
label: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(controller.value, <MaterialState>{MaterialState.hovered, MaterialState.disabled});
|
|
expect(count, 10); // removes pressed and adds disabled - two changes
|
|
await gesture.moveTo(Offset.zero);
|
|
await tester.pumpAndSettle();
|
|
expect(controller.value, <MaterialState>{MaterialState.disabled});
|
|
expect(count, 11);
|
|
await gesture.removePointer();
|
|
}
|
|
|
|
testWidgets('OutlinedButton statesController', (WidgetTester tester) async {
|
|
testStatesController(null, tester);
|
|
});
|
|
|
|
testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async {
|
|
testStatesController(const Icon(Icons.add), tester);
|
|
});
|
|
|
|
testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async {
|
|
int count = 0;
|
|
void valueChanged() {
|
|
count += 1;
|
|
}
|
|
final MaterialStatesController controller = MaterialStatesController();
|
|
controller.addListener(valueChanged);
|
|
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Center(
|
|
child: OutlinedButton(
|
|
statesController: controller,
|
|
onPressed: null,
|
|
child: const Text('button'),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
expect(controller.value, <MaterialState>{MaterialState.disabled});
|
|
expect(count, 1);
|
|
});
|
|
}
|
|
|
|
TextStyle _iconStyle(WidgetTester tester, IconData icon) {
|
|
final RichText iconRichText = tester.widget<RichText>(
|
|
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
|
|
);
|
|
return iconRichText.text.style!;
|
|
}
|