diff --git a/.ci.yaml b/.ci.yaml index dd21cb8596d0b..bbe9b2369aacc 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -29,12 +29,23 @@ platform_properties: os: Ubuntu cores: "8" device_type: none + linux_build_test: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "curl", "version": "version:7.64.0"} + ] + os: Ubuntu + cores: "8" + device_type: none linux_android: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "curl", "version": "version:7.64.0"} ] os: Linux @@ -43,8 +54,8 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "curl", "version": "version:7.64.0"} ] os: Linux @@ -53,8 +64,8 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "curl", "version": "version:7.64.0"} ] os: Linux @@ -66,14 +77,14 @@ platform_properties: os: Mac-12 device_type: none cpu: x86 - xcode: 13f17a + xcode: 14a5294e # xcode 14.0 beta 5 mac_android: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] os: Mac-12 cpu: x86 @@ -82,7 +93,7 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "open_jdk", "version": "version:11"} ] os: Mac-12 @@ -92,26 +103,26 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "apple_signing", "version": "none"} ] os: Mac-12 cpu: x86 device_os: iOS-15 - xcode: 13f17a + xcode: 14a5294e mac_arm64_ios: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "apple_signing", "version": "none"} ] os: Mac-12 cpu: arm64 device_os: iOS-15 - xcode: 13f17a + xcode: 14a5294e windows: properties: dependencies: >- @@ -124,10 +135,10 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "certs", "version": "version:9563bb"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] os: Windows-10 device_type: "msm8952" @@ -162,7 +173,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "android_virtual_device", "version": "31"} ] tags: > @@ -175,9 +186,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "version:3.16.1"}, @@ -194,9 +205,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "version:3.16.1"}, @@ -274,7 +285,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "android_sdk", "version": "version:33v6"} ] tags: > ["firebaselab"] @@ -286,7 +297,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "android_sdk", "version": "version:33v6"} ] tags: > ["firebaselab"] @@ -298,7 +309,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "android_sdk", "version": "version:33v6"} ] tags: > ["firebaselab"] @@ -350,8 +361,8 @@ targets: {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "version:3.16.1"}, {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests subshard: misc @@ -410,9 +421,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -428,9 +439,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -446,9 +457,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -464,9 +475,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -482,9 +493,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -500,9 +511,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -519,7 +530,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"} ] tags: > @@ -537,9 +548,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -556,9 +567,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -575,9 +586,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -613,7 +624,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"} ] tags: > @@ -638,10 +649,10 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: tool_integration_tests @@ -662,10 +673,10 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: tool_integration_tests @@ -686,10 +697,10 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: tool_integration_tests @@ -710,10 +721,10 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: tool_integration_tests @@ -734,8 +745,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: commands @@ -754,8 +765,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: general @@ -774,7 +785,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"} ] tags: > @@ -787,7 +798,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"} ] tags: > @@ -804,7 +815,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -824,7 +835,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -844,7 +855,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -864,7 +875,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -884,7 +895,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -904,7 +915,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -924,7 +935,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -944,7 +955,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -964,7 +975,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -984,7 +995,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1004,7 +1015,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1024,7 +1035,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1044,7 +1055,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1064,7 +1075,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1083,7 +1094,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1102,7 +1113,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1121,7 +1132,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1140,7 +1151,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1159,7 +1170,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1178,7 +1189,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1197,7 +1208,7 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] @@ -1216,9 +1227,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: web_tool_tests @@ -1412,7 +1423,7 @@ targets: task_name: complex_layout_android__compile dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout_android__scroll_smoothness @@ -1425,7 +1436,7 @@ targets: task_name: complex_layout_android__scroll_smoothness dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout_scroll_perf__devtools_memory @@ -1438,7 +1449,7 @@ targets: task_name: complex_layout_scroll_perf__devtools_memory dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout_scroll_perf__memory @@ -1451,7 +1462,7 @@ targets: task_name: complex_layout_scroll_perf__memory dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout_scroll_perf__timeline_summary @@ -1464,7 +1475,7 @@ targets: task_name: complex_layout_scroll_perf__timeline_summary dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_samsung_s10 complex_layout_scroll_perf__timeline_summary @@ -1477,7 +1488,7 @@ targets: task_name: complex_layout_scroll_perf__timeline_summary dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout_semantics_perf @@ -1490,7 +1501,7 @@ targets: task_name: complex_layout_semantics_perf dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android complex_layout__start_up @@ -1503,7 +1514,7 @@ targets: task_name: complex_layout__start_up dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android cubic_bezier_perf__e2e_summary @@ -1515,15 +1526,6 @@ targets: ["devicelab", "android", "linux"] task_name: cubic_bezier_perf__e2e_summary - - name: Linux_android cubic_bezier_perf_sksl_warmup__e2e_summary - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux"] - task_name: cubic_bezier_perf_sksl_warmup__e2e_summary - - name: Linux_samsung_s10 cubic_bezier_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false @@ -1913,7 +1915,6 @@ targets: task_name: new_gallery__crane_perf - name: Linux_android old_gallery__transition_perf - bringup: true recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -1931,14 +1932,16 @@ targets: ["devicelab", "android", "linux"] task_name: new_gallery__transition_perf - - name: Linux_android flutter_gallery__transition_perf - recipe: devicelab/devicelab_drone + - name: Linux_build_test flutter_gallery__transition_perf + recipe: devicelab/devicelab_drone_build_test presubmit: false + bringup: true # New target https://github.com/flutter/flutter/issues/103542 timeout: 60 properties: tags: > ["devicelab", "android", "linux"] task_name: flutter_gallery__transition_perf + artifact: gallery_app_profile - name: Linux_android flutter_gallery__transition_perf_e2e recipe: devicelab/devicelab_drone @@ -1967,24 +1970,6 @@ targets: ["devicelab", "android", "linux"] task_name: flutter_gallery__transition_perf_with_semantics - - name: Linux_android flutter_gallery_sksl_warmup__transition_perf - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux"] - task_name: flutter_gallery_sksl_warmup__transition_perf - - - name: Linux_android flutter_gallery_sksl_warmup__transition_perf_e2e - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux"] - task_name: flutter_gallery_sksl_warmup__transition_perf_e2e - - name: Linux_samsung_s10 new_gallery__transition_perf recipe: devicelab/devicelab_drone presubmit: false @@ -2149,7 +2134,7 @@ targets: task_name: tiles_scroll_perf__timeline_summary dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Linux_android web_size__compile_test @@ -2296,8 +2281,8 @@ targets: {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "version:3.16.1"}, {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests subshard: misc @@ -2316,13 +2301,27 @@ targets: - bin/ - .ci.yaml + - name: Mac basic_material_app_macos__compile + bringup: true # New target https://github.com/flutter/flutter/issues/109633 + presubmit: false + recipe: devicelab/devicelab_drone + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode", "version": "14a5294e"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: basic_material_app_macos__compile + - name: Mac build_ios_framework_module_test recipe: devicelab/devicelab_drone timeout: 60 properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] tags: > @@ -2335,7 +2334,6 @@ targets: - .ci.yaml - name: Mac_arm64_ios build_ios_framework_module_test - bringup: true # Flaky https://github.com/flutter/flutter/issues/105609 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -2356,13 +2354,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: build_tests subshard: "1_4" tags: > @@ -2375,13 +2377,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: build_tests subshard: "2_4" tags: > @@ -2394,13 +2400,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: build_tests subshard: "3_4" tags: > @@ -2413,18 +2423,51 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: build_tests subshard: "4_4" tags: > ["framework", "hostonly", "shard"] + - name: Mac complex_layout_macos__compile + bringup: true # New target https://github.com/flutter/flutter/issues/109633 + presubmit: false + recipe: devicelab/devicelab_drone + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode", "version": "14a5294e"}, + {"dependency": "gems", "version": "v3.3.14"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: complex_layout_macos__compile + + - name: Mac complex_layout_macos__start_up + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode", "version": "14a5294e"}, + {"dependency": "gems", "version": "v3.3.14"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: complex_layout_macos__start_up + - name: Mac customer_testing recipe: flutter/flutter timeout: 60 @@ -2441,7 +2484,7 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] tags: > @@ -2453,6 +2496,21 @@ targets: - bin/** - .ci.yaml + - name: Mac flutter_gallery_macos__compile + bringup: true # New target https://github.com/flutter/flutter/issues/109633 + presubmit: false + recipe: devicelab/devicelab_drone + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode", "version": "14a5294e"}, + {"dependency": "gems", "version": "v3.3.14"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: flutter_gallery_macos__compile + - name: Mac framework_tests_libraries recipe: flutter/flutter_drone timeout: 60 @@ -2485,10 +2543,10 @@ targets: dependencies: >- [ {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests subshard: misc @@ -2538,8 +2596,8 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -2549,14 +2607,28 @@ targets: - bin/** - .ci.yaml + - name: Mac hello_world_macos__compile + bringup: true # New target https://github.com/flutter/flutter/issues/109633 + presubmit: false + recipe: devicelab/devicelab_drone + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "xcode", "version": "14a5294e"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: hello_world_macos__compile + - name: Mac module_custom_host_app_name_test recipe: devicelab/devicelab_drone timeout: 60 properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -2573,8 +2645,8 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -2591,8 +2663,8 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -2609,9 +2681,13 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] tags: > ["devicelab", "hostonly"] task_name: module_test_ios @@ -2641,11 +2717,15 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] tags: > ["devicelab", "hostonly"] task_name: plugin_dependencies_test @@ -2661,9 +2741,13 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] tags: > ["devicelab", "hostonly"] task_name: plugin_lint_mac @@ -2699,8 +2783,8 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -2717,9 +2801,13 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] tags: > ["devicelab", "hostonly"] task_name: plugin_test_ios @@ -2736,9 +2824,13 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: tool_host_cross_arch_tests tags: > ["framework", "hostonly", "shard"] @@ -2756,13 +2848,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: tool_integration_tests subshard: "1_4" tags: > @@ -2781,13 +2877,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: tool_integration_tests subshard: "2_4" tags: > @@ -2806,13 +2906,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: tool_integration_tests subshard: "3_4" tags: > @@ -2831,13 +2935,17 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] + runtime_versions: >- + [ + "ios-16-0_14a5294e" + ] shard: tool_integration_tests subshard: "4_4" tags: > @@ -2856,8 +2964,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: commands @@ -2871,8 +2979,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: general @@ -2894,7 +3002,7 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"} + {"dependency": "xcode", "version": "14a5294e"} ] tags: > ["framework", "hostonly", "shard"] @@ -2907,9 +3015,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:98.1"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: web_tool_tests @@ -3047,6 +3155,15 @@ targets: ["devicelab", "ios", "mac"] task_name: backdrop_filter_perf_ios__timeline_summary + - name: Mac_ios backdrop_filter_perf_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: backdrop_filter_perf_impeller_ios__timeline_summary + - name: Mac_ios basic_material_app_ios__compile recipe: devicelab/devicelab_drone presubmit: false @@ -3092,14 +3209,70 @@ targets: ["devicelab", "ios", "mac"] task_name: complex_layout_scroll_perf_ios__timeline_summary - - name: Mac_ios cubic_bezier_perf_ios_sksl_warmup__timeline_summary + - name: Mac_ios complex_layout_scroll_perf_bad_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: complex_layout_scroll_perf_bad_ios__timeline_summary + + - name: Mac_ios complex_layout_scroll_perf_bad_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: complex_layout_scroll_perf_bad_impeller_ios__timeline_summary + + - name: Mac_ios complex_layout_scroll_perf_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: complex_layout_scroll_perf_impeller_ios__timeline_summary + + - name: Mac_ios color_filter_and_fade_perf_ios__e2e_summary recipe: devicelab/devicelab_drone presubmit: false timeout: 60 properties: tags: > ["devicelab", "ios", "mac"] - task_name: cubic_bezier_perf_ios_sksl_warmup__timeline_summary + task_name: color_filter_and_fade_perf_ios__e2e_summary + + - name: Mac_ios color_filter_and_fade_perf_impeller_ios__e2e_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: color_filter_and_fade_perf_impeller_ios__e2e_summary + + - name: Mac_ios imagefiltered_transform_animation_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: imagefiltered_transform_animation_perf_ios__timeline_summary + + - name: Mac_ios imagefiltered_transform_animation_perf_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: imagefiltered_transform_animation_perf_impeller_ios__timeline_summary - name: Mac_ios external_ui_integration_test_ios bringup: true # Flaky https://github.com/flutter/flutter/issues/106806 @@ -3351,6 +3524,16 @@ targets: ["devicelab", "ios", "mac"] task_name: microbenchmarks_ios + - name: Mac_ios microbenchmarks_impeller_ios + recipe: devicelab/devicelab_drone + bringup: true # Flaky: https://github.com/flutter/flutter/issues/106753 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: microbenchmarks_impeller_ios + - name: Mac_ios native_platform_view_ui_tests_ios bringup: true recipe: devicelab/devicelab_drone @@ -3442,6 +3625,15 @@ targets: ["devicelab", "ios", "mac"] task_name: platform_views_scroll_perf_ios__timeline_summary + - name: Mac_ios platform_views_scroll_perf_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: platform_views_scroll_perf_impeller_ios__timeline_summary + - name: Mac_ios post_backdrop_filter_perf_ios__timeline_summary recipe: devicelab/devicelab_drone presubmit: false @@ -3460,6 +3652,15 @@ targets: ["devicelab", "ios", "mac"] task_name: simple_animation_perf_ios + - name: Mac_ios simple_animation_perf_impeller_ios + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: simple_animation_perf_impeller_ios + - name: Mac_ios hot_mode_dev_cycle_ios__benchmark recipe: devicelab/devicelab_drone presubmit: false @@ -3469,6 +3670,24 @@ targets: ["devicelab", "ios", "mac"] task_name: hot_mode_dev_cycle_ios__benchmark + - name: Mac_ios fullscreen_textfield_perf_ios__e2e_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: fullscreen_textfield_perf_ios__e2e_summary + + - name: Mac_ios fullscreen_textfield_perf_impeller_ios__e2e_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: fullscreen_textfield_perf_impeller_ios__e2e_summary + - name: Mac_ios tiles_scroll_perf_ios__timeline_summary recipe: devicelab/devicelab_drone presubmit: false @@ -3478,13 +3697,49 @@ targets: ["devicelab", "ios", "mac"] task_name: tiles_scroll_perf_ios__timeline_summary + - name: Mac_ios tiles_scroll_perf_impeller_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: tiles_scroll_perf_impeller_ios__timeline_summary + + - name: Mac_ios flutter_gallery__transition_perf_e2e_ios + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: flutter_gallery__transition_perf_e2e_ios + + - name: Mac_ios flutter_gallery__transition_perf_e2e_impeller_ios + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: flutter_gallery__transition_perf_e2e_impeller_ios + + - name: Mac_ios flutter_gallery_ios_sksl_warmup__transition_perf + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: flutter_gallery_ios_sksl_warmup__transition_perf + - name: Mac native_ui_tests_macos recipe: devicelab/devicelab_drone timeout: 60 properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] tags: > @@ -3502,7 +3757,7 @@ targets: properties: dependencies: >- [ - {"dependency": "xcode", "version": "13f17a"}, + {"dependency": "xcode", "version": "14a5294e"}, {"dependency": "gems", "version": "v3.3.14"} ] tags: > @@ -3535,9 +3790,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3553,9 +3808,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3571,9 +3826,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3625,8 +3880,8 @@ targets: [ {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"}, - {"dependency": "open_jdk", "version": "11"}, - {"dependency": "android_sdk", "version": "version:32v1"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests subshard: misc @@ -3676,9 +3931,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3707,9 +3962,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3726,9 +3981,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3745,9 +4000,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3777,9 +4032,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3796,9 +4051,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] tags: > ["devicelab", "hostonly"] @@ -3816,9 +4071,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3840,9 +4095,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3864,9 +4119,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3888,9 +4143,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3912,9 +4167,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3936,9 +4191,9 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"}, {"dependency": "vs_build", "version": "version:vs2019"} ] @@ -3960,8 +4215,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: commands @@ -3980,8 +4235,8 @@ targets: add_recipes_cq: "true" dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, - {"dependency": "open_jdk", "version": "11"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_tests subshard: general @@ -3999,9 +4254,9 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:32v1"}, + {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:96.2"}, - {"dependency": "open_jdk", "version": "11"}, + {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:3a77d0b12c697a840ca0c7705208e8622dc94603"} ] shard: web_tool_tests @@ -4028,7 +4283,7 @@ targets: - name: Windows hello_world_win_desktop__compile recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4041,7 +4296,7 @@ targets: - name: Windows flutter_gallery_win_desktop__compile recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4054,7 +4309,7 @@ targets: - name: Windows flutter_gallery_win_desktop__start_up recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4067,7 +4322,7 @@ targets: - name: Windows complex_layout_win_desktop__compile recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4080,7 +4335,7 @@ targets: - name: Windows complex_layout_win_desktop__start_up recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4093,7 +4348,7 @@ targets: - name: Windows flutter_view_win_desktop__start_up recipe: devicelab/devicelab_drone - bringup: true # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false timeout: 60 properties: tags: > @@ -4106,8 +4361,8 @@ targets: - name: Windows platform_view_win_desktop__start_up recipe: devicelab/devicelab_drone - bringup: true - timeout: 60 # New target https://github.com/flutter/flutter/issues/70027 + presubmit: false + timeout: 60 properties: tags: > ["devicelab", "hostonly"] @@ -4146,7 +4401,7 @@ targets: task_name: complex_layout_win__compile dependencies: >- [ - {"dependency": "open_jdk", "version": "11"} + {"dependency": "open_jdk", "version": "version:11"} ] - name: Windows_android flavors_test_win @@ -4185,3 +4440,16 @@ targets: tags: > ["devicelab", "android", "windows"] task_name: windows_chrome_dev_mode + + - name: Windows windows_startup_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + tags: > + ["devicelab", "hostonly"] + task_name: windows_startup_test diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 611bb5911a265..f8764d1174543 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -32,7 +32,6 @@ updates: schedule: interval: "daily" reviewers: - - "hixie" - "godofredoc" labels: - "team" diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index a629695cea7e4..6ce54706087d9 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -49,6 +49,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2ca79b6fa8d3ec278944088b4aa5f46912db5d63 + uses: github/codeql-action/upload-sarif@b398f525a5587552e573b247ac661067fafa920b with: sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 0ed355f5bfeb1..de64807b21241 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,10 @@ unlinked_spec.ds **/macos/Flutter/ephemeral **/xcuserdata/ +# Windows +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h + # Coverage coverage/ diff --git a/TESTOWNERS b/TESTOWNERS index 95ee36fe569cf..dc14a4d9e7f4f 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -142,26 +142,38 @@ /dev/devicelab/bin/tasks/tiles_scroll_perf__timeline_summary.dart @zanderso @flutter/engine ## Mac iOS DeviceLab tests +/dev/devicelab/bin/tasks/animated_complex_opacity_perf_impeller_ios__e2e_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/animated_complex_opacity_perf_ios__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/animation_with_microtasks_perf_ios__timeline_summary.dart @iskakaushik @flutter/engine +/dev/devicelab/bin/tasks/backdrop_filter_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/backdrop_filter_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/basic_material_app_ios__compile.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/channels_integration_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/codegen_integration_mac.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/color_filter_and_fade_perf_impeller_ios__e2e_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/color_filter_and_fade_perf_ios__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/complex_layout_ios__compile.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_impeller_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/external_ui_integration_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flavors_test_ios.dart @jmagman @flutter/tool +/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_impeller_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios__compile.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart @zanderso @flutter/engine -/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios_sksl_warmup__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/fullscreen_textfield_perf_impeller_ios__e2e_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/fullscreen_textfield_perf_ios__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world_ios__compile.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hot_mode_dev_cycle_ios__benchmark.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/hot_mode_dev_cycle_macos_target__benchmark.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/integration_test_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/integration_ui_ios_driver.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/integration_ui_ios_frame_number.dart @iskakaushik @flutter/engine @@ -175,20 +187,24 @@ /dev/devicelab/bin/tasks/ios_platform_view_tests.dart @stuartmorgan @flutter/plugin /dev/devicelab/bin/tasks/large_image_changer_perf_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/macos_chrome_dev_mode.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/microbenchmarks_impeller_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/microbenchmarks_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/native_platform_view_ui_tests_ios.dart @hellohuanlin @flutter/ios -/dev/devicelab/bin/tasks/new_gallery_ios__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/new_gallery_impeller_ios__transition_perf.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/new_gallery_ios__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_channel_sample_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_channel_sample_test_swift.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_channels_benchmarks_ios.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/platform_interaction_test_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_view_ios__start_up.dart @stuartmorgan @flutter/plugin +/dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_views_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/post_backdrop_filter_perf_ios__timeline_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/route_test_ios.dart @jasguerrero @flutter/tool +/dev/devicelab/bin/tasks/simple_animation_perf_impeller_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/simple_animation_perf_ios.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/tiles_scroll_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/tiles_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine -/dev/devicelab/bin/tasks/route_test_ios.dart @jasguerrero @flutter/tool ## Host only DeviceLab tests /dev/devicelab/bin/tasks/build_aar_module_test.dart @zanderso @flutter/tool @@ -219,13 +235,19 @@ /dev/devicelab/bin/tasks/run_release_test_macos.dart @cbracken @flutter/tool /dev/devicelab/bin/tasks/entrypoint_dart_registrant.dart @aaclarke @flutter/plugin /dev/devicelab/bin/tasks/windows_home_scroll_perf__timeline_summary.dart @jonahwilliams @flutter/engine -/dev/devicelab/bin/tasks/hello_world_win_desktop__compile.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/flutter_gallery_win_desktop__compile.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/flutter_gallery_win_desktop__start_up.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/complex_layout_win_desktop__compile.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/complex_layout_win_desktop__start_up.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/flutter_view_win_desktop__start_up.dart @schectman @flutter/desktop -/dev/devicelab/bin/tasks/platform_view_win_desktop__start_up.dart @schectman @flutter/desktop +/dev/devicelab/bin/tasks/hello_world_win_desktop__compile.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/flutter_gallery_win_desktop__compile.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/flutter_gallery_win_desktop__start_up.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/complex_layout_win_desktop__compile.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/complex_layout_win_desktop__start_up.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/flutter_view_win_desktop__start_up.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/platform_view_win_desktop__start_up.dart @yaakovschectman @flutter/desktop +/dev/devicelab/bin/tasks/hello_world_macos__compile.dart @a-wallen @flutter/desktop +/dev/devicelab/bin/tasks/basic_material_app_macos__compile.dart @a-wallen @flutter/desktop +/dev/devicelab/bin/tasks/complex_layout_macos__start_up.dart @a-wallen @flutter/desktop +/dev/devicelab/bin/tasks/windows_startup_test.dart @loic-sharma @flutter/desktop +/dev/devicelab/bin/tasks/complex_layout_macos__compile.dart @a-wallen @flutter/desktop +/dev/devicelab/bin/tasks/flutter_gallery_macos__compile.dart @a-wallen @flutter/desktop ## Host only framework tests # Linux analyze diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 05374e3f26ff4..94adba5ab985f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1311fea574d64b37e42c2ba5e16f7872671233d7 +ce97b5a7f944157e9b2eeefa6101a7c1f102240e diff --git a/bin/internal/flutter_plugins.version b/bin/internal/flutter_plugins.version index ce32eb430f9ab..cea1db002fcb7 100644 --- a/bin/internal/flutter_plugins.version +++ b/bin/internal/flutter_plugins.version @@ -1 +1 @@ -4395e3195be7cefc404b4fa9851b6cdbe90e3b2e +c6b2f8a844394f522d634a253c050537ea0252ac diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 2002903277149..db67477475a62 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -gqQZ7EN2TeYTzOqKIjxGXNNpoDcz68MXn-l9Vtg2fYoC +ZBIe-a1gc3wZOjrZFZ_37KJqGyw0f6KBELaJaZBsgboC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c0f908e1e7c34..7a96f69462060 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -1hIAHHOhq9Acf2u3dwEe2__qTlaQTSxxm5o6s_RK1qMC +vxuLLecT-NU8FuW1lAbXNg5iDOvKWw9cYQrLIi2vMFAC diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index e3689631c32ec..3323470a604ec 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -13,10 +13,10 @@ dependencies: integration_test: sdk: flutter platform: 3.1.0 - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,8 +27,8 @@ dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,14 +56,14 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -71,4 +71,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 927f +# PUBSPEC CHECKSUM: 7784 diff --git a/dev/benchmarks/complex_layout/lib/main.dart b/dev/benchmarks/complex_layout/lib/main.dart index c99261e1995b0..ac618e58c1452 100644 --- a/dev/benchmarks/complex_layout/lib/main.dart +++ b/dev/benchmarks/complex_layout/lib/main.dart @@ -2,696 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart' show timeDilation; +import 'package:flutter/widgets.dart'; +import 'src/app.dart'; void main() { runApp( const ComplexLayoutApp() ); } - -enum ScrollMode { complex, tile } - -class ComplexLayoutApp extends StatefulWidget { - const ComplexLayoutApp({super.key}); - - @override - ComplexLayoutAppState createState() => ComplexLayoutAppState(); - - static ComplexLayoutAppState? of(BuildContext context) => context.findAncestorStateOfType(); -} - -class ComplexLayoutAppState extends State { - @override - Widget build(BuildContext context) { - return MaterialApp( - theme: lightTheme ? ThemeData.light() : ThemeData.dark(), - title: 'Advanced Layout', - home: scrollMode == ScrollMode.complex ? const ComplexLayout() : const TileScrollLayout()); - } - - bool _lightTheme = true; - bool get lightTheme => _lightTheme; - set lightTheme(bool value) { - setState(() { - _lightTheme = value; - }); - } - - ScrollMode _scrollMode = ScrollMode.complex; - ScrollMode get scrollMode => _scrollMode; - set scrollMode(ScrollMode mode) { - setState(() { - _scrollMode = mode; - }); - } - - void toggleAnimationSpeed() { - setState(() { - timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0; - }); - } -} - -class TileScrollLayout extends StatelessWidget { - const TileScrollLayout({ super.key }); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Tile Scrolling Layout')), - body: ListView.builder( - key: const Key('tiles-scroll'), - itemCount: 200, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.all(5.0), - child: Material( - elevation: (index % 5 + 1).toDouble(), - color: Colors.white, - child: const IconBar(), - ), - ); - }, - ), - drawer: const GalleryDrawer(), - ); - } -} - -class ComplexLayout extends StatefulWidget { - const ComplexLayout({ super.key }); - - @override - ComplexLayoutState createState() => ComplexLayoutState(); - - static ComplexLayoutState? of(BuildContext context) => context.findAncestorStateOfType(); -} - -class ComplexLayoutState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Advanced Layout'), - actions: [ - IconButton( - icon: const Icon(Icons.create), - tooltip: 'Search', - onPressed: () { - print('Pressed search'); - }, - ), - const TopBarMenu(), - ], - ), - body: Column( - children: [ - Expanded( - child: ListView.builder( - key: const Key('complex-scroll'), // this key is used by the driver test - controller: ScrollController(), // So that the scroll offset can be tracked - itemBuilder: (BuildContext context, int index) { - if (index.isEven) { - return FancyImageItem(index, key: PageStorageKey(index)); - } else { - return FancyGalleryItem(index, key: PageStorageKey(index)); - } - }, - ), - ), - const BottomBar(), - ], - ), - drawer: const GalleryDrawer(), - ); - } -} - -class TopBarMenu extends StatelessWidget { - const TopBarMenu({super.key}); - - @override - Widget build(BuildContext context) { - return PopupMenuButton( - onSelected: (String value) { print('Selected: $value'); }, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - value: 'Friends', - child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.group, 'Groups', '14'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), - ), - const PopupMenuItem( - value: 'Friends', - child: MenuItemWithIcon(Icons.people, 'Friends', '5'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.event, 'Events', '12'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.group, 'Groups', '14'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), - ), - const PopupMenuItem( - value: 'Events', - child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), - ), - ], - ); - } -} - -class MenuItemWithIcon extends StatelessWidget { - const MenuItemWithIcon(this.icon, this.title, this.subtitle, {super.key}); - - final IconData icon; - final String title; - final String subtitle; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Icon(icon), - Padding( - padding: const EdgeInsets.only(left: 8.0, right: 8.0), - child: Text(title), - ), - Text(subtitle, style: Theme.of(context).textTheme.caption), - ], - ); - } -} - -class FancyImageItem extends StatelessWidget { - const FancyImageItem(this.index, {super.key}); - - final int index; - - @override - Widget build(BuildContext context) { - return ListBody( - children: [ - UserHeader('Ali Connors $index'), - const ItemDescription(), - const ItemImageBox(), - const InfoBar(), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0), - child: Divider(), - ), - const IconBar(), - const FatDivider(), - ], - ); - } -} - -class FancyGalleryItem extends StatelessWidget { - const FancyGalleryItem(this.index, {super.key}); - - final int index; - @override - Widget build(BuildContext context) { - return ListBody( - children: [ - const UserHeader('Ali Connors'), - ItemGalleryBox(index), - const InfoBar(), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0), - child: Divider(), - ), - const IconBar(), - const FatDivider(), - ], - ); - } -} - -class InfoBar extends StatelessWidget { - const InfoBar({super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const MiniIconWithText(Icons.thumb_up, '42'), - Text('3 Comments', style: Theme.of(context).textTheme.caption), - ], - ), - ); - } -} - -class IconBar extends StatelessWidget { - const IconBar({super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 16.0, right: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: const [ - IconWithText(Icons.thumb_up, 'Like'), - IconWithText(Icons.comment, 'Comment'), - IconWithText(Icons.share, 'Share'), - ], - ), - ); - } -} - -class IconWithText extends StatelessWidget { - const IconWithText(this.icon, this.title, {super.key}); - - final IconData icon; - final String title; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: Icon(icon), - onPressed: () { print('Pressed $title button'); }, - ), - Text(title), - ], - ); - } -} - -class MiniIconWithText extends StatelessWidget { - const MiniIconWithText(this.icon, this.title, {super.key}); - - final IconData icon; - final String title; - - @override - Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Container( - width: 16.0, - height: 16.0, - decoration: ShapeDecoration( - color: Theme.of(context).primaryColor, - shape: const CircleBorder(), - ), - child: Icon(icon, color: Colors.white, size: 12.0), - ), - ), - Text(title, style: Theme.of(context).textTheme.caption), - ], - ); - } -} - -class FatDivider extends StatelessWidget { - const FatDivider({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - height: 8.0, - color: Theme.of(context).dividerColor, - ); - } -} - -class UserHeader extends StatelessWidget { - const UserHeader(this.userName, {super.key}); - - final String userName; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.only(right: 8.0), - child: Image( - image: AssetImage('packages/flutter_gallery_assets/people/square/ali.png'), - width: 32.0, - height: 32.0, - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - RichText(text: TextSpan( - style: Theme.of(context).textTheme.bodyText2, - children: [ - TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)), - const TextSpan(text: ' shared a new '), - const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)), - ], - )), - Row( - children: [ - Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.caption), - Icon(Icons.people, size: 16.0, color: Theme.of(context).textTheme.caption!.color), - ], - ), - ], - ), - ), - const TopBarMenu(), - ], - ), - ); - } -} - -class ItemDescription extends StatelessWidget { - const ItemDescription({super.key}); - - @override - Widget build(BuildContext context) { - return const Padding( - padding: EdgeInsets.all(8.0), - child: Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'), - ); - } -} - -class ItemImageBox extends StatelessWidget { - const ItemImageBox({super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - children: [ - const SizedBox( - height: 230.0, - child: Image( - image: AssetImage('packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png') - ), - ), - Theme( - data: ThemeData.dark(), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { print('Pressed edit button'); }, - ), - IconButton( - icon: const Icon(Icons.zoom_in), - onPressed: () { print('Pressed zoom button'); }, - ), - ], - ), - ), - Positioned( - bottom: 4.0, - left: 4.0, - child: Container( - decoration: BoxDecoration( - color: Colors.black54, - borderRadius: BorderRadius.circular(2.0), - ), - padding: const EdgeInsets.all(4.0), - child: RichText( - text: const TextSpan( - style: TextStyle(color: Colors.white), - children: [ - TextSpan( - text: 'Photo by ' - ), - TextSpan( - style: TextStyle(fontWeight: FontWeight.bold), - text: 'Chris Godley', - ), - ], - ), - ), - ), - ), - ], - ) - , - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text('Artisans of Southern India', style: Theme.of(context).textTheme.bodyText1), - Text('Silk Spinners', style: Theme.of(context).textTheme.bodyText2), - Text('Sivaganga, Tamil Nadu', style: Theme.of(context).textTheme.caption), - ], - ), - ), - ], - ), - ), - ); - } -} - -class ItemGalleryBox extends StatelessWidget { - const ItemGalleryBox(this.index, {super.key}); - - final int index; - - @override - Widget build(BuildContext context) { - final List tabNames = [ - 'A', 'B', 'C', 'D', - ]; - - return SizedBox( - height: 200.0, - child: DefaultTabController( - length: tabNames.length, - child: Column( - children: [ - Expanded( - child: TabBarView( - children: tabNames.map((String tabName) { - return Container( - key: PageStorageKey(tabName), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - child: Column( - children: [ - Expanded( - child: Container( - color: Theme.of(context).primaryColor, - child: Center( - child: Text(tabName, style: Theme.of(context).textTheme.headline5!.copyWith(color: Colors.white)), - ), - ), - ), - Row( - children: [ - IconButton( - icon: const Icon(Icons.share), - onPressed: () { print('Pressed share'); }, - ), - IconButton( - icon: const Icon(Icons.event), - onPressed: () { print('Pressed event'); }, - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text('This is item $tabName'), - ), - ), - ], - ), - ], - ), - ), - ), - ); - }).toList(), - ), - ), - const TabPageSelector(), - ], - ), - ), - ); - } -} - -class BottomBar extends StatelessWidget { - const BottomBar({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: Theme.of(context).dividerColor, - ), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: const [ - BottomBarButton(Icons.new_releases, 'News'), - BottomBarButton(Icons.people, 'Requests'), - BottomBarButton(Icons.chat, 'Messenger'), - BottomBarButton(Icons.bookmark, 'Bookmark'), - BottomBarButton(Icons.alarm, 'Alarm'), - ], - ), - ); - } -} - -class BottomBarButton extends StatelessWidget { - const BottomBarButton(this.icon, this.title, {super.key}); - - final IconData icon; - final String title; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - IconButton( - icon: Icon(icon), - onPressed: () { print('Pressed: $title'); }, - ), - Text(title, style: Theme.of(context).textTheme.caption), - ], - ), - ); - } -} - -class GalleryDrawer extends StatelessWidget { - const GalleryDrawer({ super.key }); - - void _changeTheme(BuildContext context, bool value) { - ComplexLayoutApp.of(context)?.lightTheme = value; - } - - void _changeScrollMode(BuildContext context, ScrollMode mode) { - ComplexLayoutApp.of(context)?.scrollMode = mode; - } - - @override - Widget build(BuildContext context) { - final ScrollMode currentMode = ComplexLayoutApp.of(context)!.scrollMode; - return Drawer( - // Note: for real apps, see the Gallery material Drawer demo. More - // typically, a drawer would have a fixed header with a scrolling body - // below it. - child: ListView( - key: const PageStorageKey('gallery-drawer'), - padding: EdgeInsets.zero, - children: [ - const FancyDrawerHeader(), - ListTile( - key: const Key('scroll-switcher'), - title: const Text('Scroll Mode'), - onTap: () { - _changeScrollMode(context, currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex); - Navigator.pop(context); - }, - trailing: Text(currentMode == ScrollMode.complex ? 'Tile' : 'Complex'), - ), - ListTile( - leading: const Icon(Icons.brightness_5), - title: const Text('Light'), - onTap: () { _changeTheme(context, true); }, - selected: ComplexLayoutApp.of(context)!.lightTheme, - trailing: Radio( - value: true, - groupValue: ComplexLayoutApp.of(context)!.lightTheme, - onChanged: (bool? value) { _changeTheme(context, value!); }, - ), - ), - ListTile( - leading: const Icon(Icons.brightness_7), - title: const Text('Dark'), - onTap: () { _changeTheme(context, false); }, - selected: !ComplexLayoutApp.of(context)!.lightTheme, - trailing: Radio( - value: false, - groupValue: ComplexLayoutApp.of(context)!.lightTheme, - onChanged: (bool? value) { _changeTheme(context, value!); }, - ), - ), - const Divider(), - ListTile( - leading: const Icon(Icons.hourglass_empty), - title: const Text('Animate Slowly'), - selected: timeDilation != 1.0, - onTap: () { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, - trailing: Checkbox( - value: timeDilation != 1.0, - onChanged: (bool? value) { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, - ), - ), - ], - ), - ); - } -} - -class FancyDrawerHeader extends StatelessWidget { - const FancyDrawerHeader({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - color: Colors.purple, - height: 200.0, - child: const SafeArea( - bottom: false, - child: Placeholder(), - ), - ); - } -} diff --git a/dev/benchmarks/complex_layout/lib/main_bad.dart b/dev/benchmarks/complex_layout/lib/main_bad.dart new file mode 100644 index 0000000000000..5b2d5f627c02b --- /dev/null +++ b/dev/benchmarks/complex_layout/lib/main_bad.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'src/app.dart'; + +void main() { + runApp( + const ComplexLayoutApp(badScroll: true) + ); +} diff --git a/dev/benchmarks/complex_layout/lib/src/app.dart b/dev/benchmarks/complex_layout/lib/src/app.dart new file mode 100644 index 0000000000000..21c03d6d807ca --- /dev/null +++ b/dev/benchmarks/complex_layout/lib/src/app.dart @@ -0,0 +1,703 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart' show timeDilation; + +enum ScrollMode { complex, tile } + +class ComplexLayoutApp extends StatefulWidget { + const ComplexLayoutApp({super.key, this.badScroll = false}); + + final bool badScroll; + + @override + ComplexLayoutAppState createState() => ComplexLayoutAppState(); + + static ComplexLayoutAppState? of(BuildContext context) => context.findAncestorStateOfType(); +} + +class ComplexLayoutAppState extends State { + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: lightTheme ? ThemeData.light() : ThemeData.dark(), + title: 'Advanced Layout', + home: scrollMode == ScrollMode.complex ? ComplexLayout(badScroll: widget.badScroll) : const TileScrollLayout()); + } + + bool _lightTheme = true; + bool get lightTheme => _lightTheme; + set lightTheme(bool value) { + setState(() { + _lightTheme = value; + }); + } + + ScrollMode _scrollMode = ScrollMode.complex; + ScrollMode get scrollMode => _scrollMode; + set scrollMode(ScrollMode mode) { + setState(() { + _scrollMode = mode; + }); + } + + void toggleAnimationSpeed() { + setState(() { + timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0; + }); + } +} + +class TileScrollLayout extends StatelessWidget { + const TileScrollLayout({ super.key }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Tile Scrolling Layout')), + body: ListView.builder( + key: const Key('tiles-scroll'), + itemCount: 200, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(5.0), + child: Material( + elevation: (index % 5 + 1).toDouble(), + color: Colors.white, + child: const IconBar(), + ), + ); + }, + ), + drawer: const GalleryDrawer(), + ); + } +} + +class ComplexLayout extends StatefulWidget { + const ComplexLayout({ super.key, required this.badScroll }); + + final bool badScroll; + + @override + ComplexLayoutState createState() => ComplexLayoutState(); + + static ComplexLayoutState? of(BuildContext context) => context.findAncestorStateOfType(); +} + +class ComplexLayoutState extends State { + @override + Widget build(BuildContext context) { + Widget body = ListView.builder( + key: const Key('complex-scroll'), // this key is used by the driver test + controller: ScrollController(), // So that the scroll offset can be tracked + itemCount: widget.badScroll ? 500 : null, + shrinkWrap: widget.badScroll, + itemBuilder: (BuildContext context, int index) { + if (index.isEven) { + return FancyImageItem(index, key: PageStorageKey(index)); + } else { + return FancyGalleryItem(index, key: PageStorageKey(index)); + } + }, + ); + if (widget.badScroll) { + body = ListView( + key: const Key('complex-scroll-bad'), + children: [body], + ); + } + + return Scaffold( + appBar: AppBar( + title: const Text('Advanced Layout'), + actions: [ + IconButton( + icon: const Icon(Icons.create), + tooltip: 'Search', + onPressed: () { + print('Pressed search'); + }, + ), + const TopBarMenu(), + ], + ), + body: Column( + children: [ + Expanded(child: body), + const BottomBar(), + ], + ), + drawer: const GalleryDrawer(), + ); + } +} + +class TopBarMenu extends StatelessWidget { + const TopBarMenu({super.key}); + + @override + Widget build(BuildContext context) { + return PopupMenuButton( + onSelected: (String value) { print('Selected: $value'); }, + itemBuilder: (BuildContext context) => >[ + const PopupMenuItem( + value: 'Friends', + child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.group, 'Groups', '14'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), + ), + const PopupMenuItem( + value: 'Friends', + child: MenuItemWithIcon(Icons.people, 'Friends', '5'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.event, 'Events', '12'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.group, 'Groups', '14'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.image, 'Pictures', '12'), + ), + const PopupMenuItem( + value: 'Events', + child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'), + ), + ], + ); + } +} + +class MenuItemWithIcon extends StatelessWidget { + const MenuItemWithIcon(this.icon, this.title, this.subtitle, {super.key}); + + final IconData icon; + final String title; + final String subtitle; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Icon(icon), + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: Text(title), + ), + Text(subtitle, style: Theme.of(context).textTheme.bodySmall), + ], + ); + } +} + +class FancyImageItem extends StatelessWidget { + const FancyImageItem(this.index, {super.key}); + + final int index; + + @override + Widget build(BuildContext context) { + return ListBody( + children: [ + UserHeader('Ali Connors $index'), + const ItemDescription(), + const ItemImageBox(), + const InfoBar(), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: Divider(), + ), + const IconBar(), + const FatDivider(), + ], + ); + } +} + +class FancyGalleryItem extends StatelessWidget { + const FancyGalleryItem(this.index, {super.key}); + + final int index; + @override + Widget build(BuildContext context) { + return ListBody( + children: [ + const UserHeader('Ali Connors'), + ItemGalleryBox(index), + const InfoBar(), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: Divider(), + ), + const IconBar(), + const FatDivider(), + ], + ); + } +} + +class InfoBar extends StatelessWidget { + const InfoBar({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const MiniIconWithText(Icons.thumb_up, '42'), + Text('3 Comments', style: Theme.of(context).textTheme.bodySmall), + ], + ), + ); + } +} + +class IconBar extends StatelessWidget { + const IconBar({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 16.0, right: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + IconWithText(Icons.thumb_up, 'Like'), + IconWithText(Icons.comment, 'Comment'), + IconWithText(Icons.share, 'Share'), + ], + ), + ); + } +} + +class IconWithText extends StatelessWidget { + const IconWithText(this.icon, this.title, {super.key}); + + final IconData icon; + final String title; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(icon), + onPressed: () { print('Pressed $title button'); }, + ), + Text(title), + ], + ); + } +} + +class MiniIconWithText extends StatelessWidget { + const MiniIconWithText(this.icon, this.title, {super.key}); + + final IconData icon; + final String title; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Container( + width: 16.0, + height: 16.0, + decoration: ShapeDecoration( + color: Theme.of(context).primaryColor, + shape: const CircleBorder(), + ), + child: Icon(icon, color: Colors.white, size: 12.0), + ), + ), + Text(title, style: Theme.of(context).textTheme.bodySmall), + ], + ); + } +} + +class FatDivider extends StatelessWidget { + const FatDivider({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + height: 8.0, + color: Theme.of(context).dividerColor, + ); + } +} + +class UserHeader extends StatelessWidget { + const UserHeader(this.userName, {super.key}); + + final String userName; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only(right: 8.0), + child: Image( + image: AssetImage('packages/flutter_gallery_assets/people/square/ali.png'), + width: 32.0, + height: 32.0, + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + RichText(text: TextSpan( + style: Theme.of(context).textTheme.bodyMedium, + children: [ + TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)), + const TextSpan(text: ' shared a new '), + const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)), + ], + )), + Row( + children: [ + Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.bodySmall), + Icon(Icons.people, size: 16.0, color: Theme.of(context).textTheme.bodySmall!.color), + ], + ), + ], + ), + ), + const TopBarMenu(), + ], + ), + ); + } +} + +class ItemDescription extends StatelessWidget { + const ItemDescription({super.key}); + + @override + Widget build(BuildContext context) { + return const Padding( + padding: EdgeInsets.all(8.0), + child: Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'), + ); + } +} + +class ItemImageBox extends StatelessWidget { + const ItemImageBox({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + const SizedBox( + height: 230.0, + child: Image( + image: AssetImage('packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png') + ), + ), + Theme( + data: ThemeData.dark(), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { print('Pressed edit button'); }, + ), + IconButton( + icon: const Icon(Icons.zoom_in), + onPressed: () { print('Pressed zoom button'); }, + ), + ], + ), + ), + Positioned( + bottom: 4.0, + left: 4.0, + child: Container( + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: BorderRadius.circular(2.0), + ), + padding: const EdgeInsets.all(4.0), + child: RichText( + text: const TextSpan( + style: TextStyle(color: Colors.white), + children: [ + TextSpan( + text: 'Photo by ' + ), + TextSpan( + style: TextStyle(fontWeight: FontWeight.bold), + text: 'Chris Godley', + ), + ], + ), + ), + ), + ), + ], + ) + , + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text('Artisans of Southern India', style: Theme.of(context).textTheme.bodyLarge), + Text('Silk Spinners', style: Theme.of(context).textTheme.bodyMedium), + Text('Sivaganga, Tamil Nadu', style: Theme.of(context).textTheme.bodySmall), + ], + ), + ), + ], + ), + ), + ); + } +} + +class ItemGalleryBox extends StatelessWidget { + const ItemGalleryBox(this.index, {super.key}); + + final int index; + + @override + Widget build(BuildContext context) { + final List tabNames = [ + 'A', 'B', 'C', 'D', + ]; + + return SizedBox( + height: 200.0, + child: DefaultTabController( + length: tabNames.length, + child: Column( + children: [ + Expanded( + child: TabBarView( + children: tabNames.map((String tabName) { + return Container( + key: PageStorageKey(tabName), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + child: Column( + children: [ + Expanded( + child: Container( + color: Theme.of(context).primaryColor, + child: Center( + child: Text(tabName, style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white)), + ), + ), + ), + Row( + children: [ + IconButton( + icon: const Icon(Icons.share), + onPressed: () { print('Pressed share'); }, + ), + IconButton( + icon: const Icon(Icons.event), + onPressed: () { print('Pressed event'); }, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text('This is item $tabName'), + ), + ), + ], + ), + ], + ), + ), + ), + ); + }).toList(), + ), + ), + const TabPageSelector(), + ], + ), + ), + ); + } +} + +class BottomBar extends StatelessWidget { + const BottomBar({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Theme.of(context).dividerColor, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + BottomBarButton(Icons.new_releases, 'News'), + BottomBarButton(Icons.people, 'Requests'), + BottomBarButton(Icons.chat, 'Messenger'), + BottomBarButton(Icons.bookmark, 'Bookmark'), + BottomBarButton(Icons.alarm, 'Alarm'), + ], + ), + ); + } +} + +class BottomBarButton extends StatelessWidget { + const BottomBarButton(this.icon, this.title, {super.key}); + + final IconData icon; + final String title; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + IconButton( + icon: Icon(icon), + onPressed: () { print('Pressed: $title'); }, + ), + Text(title, style: Theme.of(context).textTheme.bodySmall), + ], + ), + ); + } +} + +class GalleryDrawer extends StatelessWidget { + const GalleryDrawer({ super.key }); + + void _changeTheme(BuildContext context, bool value) { + ComplexLayoutApp.of(context)?.lightTheme = value; + } + + void _changeScrollMode(BuildContext context, ScrollMode mode) { + ComplexLayoutApp.of(context)?.scrollMode = mode; + } + + @override + Widget build(BuildContext context) { + final ScrollMode currentMode = ComplexLayoutApp.of(context)!.scrollMode; + return Drawer( + // Note: for real apps, see the Gallery material Drawer demo. More + // typically, a drawer would have a fixed header with a scrolling body + // below it. + child: ListView( + key: const PageStorageKey('gallery-drawer'), + padding: EdgeInsets.zero, + children: [ + const FancyDrawerHeader(), + ListTile( + key: const Key('scroll-switcher'), + title: const Text('Scroll Mode'), + onTap: () { + _changeScrollMode(context, currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex); + Navigator.pop(context); + }, + trailing: Text(currentMode == ScrollMode.complex ? 'Tile' : 'Complex'), + ), + ListTile( + leading: const Icon(Icons.brightness_5), + title: const Text('Light'), + onTap: () { _changeTheme(context, true); }, + selected: ComplexLayoutApp.of(context)!.lightTheme, + trailing: Radio( + value: true, + groupValue: ComplexLayoutApp.of(context)!.lightTheme, + onChanged: (bool? value) { _changeTheme(context, value!); }, + ), + ), + ListTile( + leading: const Icon(Icons.brightness_7), + title: const Text('Dark'), + onTap: () { _changeTheme(context, false); }, + selected: !ComplexLayoutApp.of(context)!.lightTheme, + trailing: Radio( + value: false, + groupValue: ComplexLayoutApp.of(context)!.lightTheme, + onChanged: (bool? value) { _changeTheme(context, value!); }, + ), + ), + const Divider(), + ListTile( + leading: const Icon(Icons.hourglass_empty), + title: const Text('Animate Slowly'), + selected: timeDilation != 1.0, + onTap: () { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, + trailing: Checkbox( + value: timeDilation != 1.0, + onChanged: (bool? value) { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); }, + ), + ), + ], + ), + ); + } +} + +class FancyDrawerHeader extends StatelessWidget { + const FancyDrawerHeader({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.purple, + height: 200.0, + child: const SafeArea( + bottom: false, + child: Placeholder(), + ), + ); + } +} diff --git a/dev/benchmarks/complex_layout/macos/.gitignore b/dev/benchmarks/complex_layout/macos/.gitignore new file mode 100644 index 0000000000000..1c4d2a9e3db13 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/.gitignore @@ -0,0 +1,10 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ + +# Portable Network Graphics +*.png diff --git a/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Debug.xcconfig b/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000000..4b81f9b2d200f --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Release.xcconfig b/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000000..5caa9d1579e48 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dev/benchmarks/complex_layout/macos/Podfile b/dev/benchmarks/complex_layout/macos/Podfile new file mode 100644 index 0000000000000..fe733905db657 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.13' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.pbxproj b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..06b2ea006390c --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,615 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + A9A44C30118C620213F67668 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B07707A6984908B7652042D8 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0E765F993B271AAE72209DBD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* complex_layout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = complex_layout.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 624FB70330494D363BDCF322 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A00AB91C052CA143B5A30FEA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + B07707A6984908B7652042D8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A9A44C30118C620213F67668 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 64E5239F9235D2213204B2B1 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* complex_layout.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 64E5239F9235D2213204B2B1 /* Pods */ = { + isa = PBXGroup; + children = ( + A00AB91C052CA143B5A30FEA /* Pods-Runner.debug.xcconfig */, + 624FB70330494D363BDCF322 /* Pods-Runner.release.xcconfig */, + 0E765F993B271AAE72209DBD /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + B07707A6984908B7652042D8 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 4115E3D8C3F847C26E6D7B2B /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* complex_layout.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 4115E3D8C3F847C26E6D7B2B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000000..7a28fb0b1cbc5 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/contents.xcworkspacedata b/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000..21a3cc14c74e9 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner/AppDelegate.swift b/dev/benchmarks/complex_layout/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000000..d080d41951d35 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/dev/benchmarks/complex_layout/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/benchmarks/complex_layout/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000..a2ec33f19f110 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/dev/benchmarks/complex_layout/macos/Runner/Base.lproj/MainMenu.xib b/dev/benchmarks/complex_layout/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000000..80e867a4e06b4 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner/Configs/AppInfo.xcconfig b/dev/benchmarks/complex_layout/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000000..529c3d4f0b681 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = complex_layout + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.complexLayout + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright 2014 The Flutter Authors. All rights reserved. diff --git a/dev/benchmarks/complex_layout/macos/Runner/Configs/Debug.xcconfig b/dev/benchmarks/complex_layout/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000000..36b0fd9464f45 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/dev/benchmarks/complex_layout/macos/Runner/Configs/Release.xcconfig b/dev/benchmarks/complex_layout/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000000..dff4f49561c81 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/dev/benchmarks/complex_layout/macos/Runner/Configs/Warnings.xcconfig b/dev/benchmarks/complex_layout/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000000..42bcbf4780b18 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/dev/benchmarks/complex_layout/macos/Runner/DebugProfile.entitlements b/dev/benchmarks/complex_layout/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000000..dddb8a30c851e --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/dev/benchmarks/complex_layout/macos/Runner/Info.plist b/dev/benchmarks/complex_layout/macos/Runner/Info.plist new file mode 100644 index 0000000000000..4789daa6a443e --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/dev/benchmarks/complex_layout/macos/Runner/MainFlutterWindow.swift b/dev/benchmarks/complex_layout/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000000..a97a96274ee93 --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,19 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/dev/benchmarks/complex_layout/macos/Runner/Release.entitlements b/dev/benchmarks/complex_layout/macos/Runner/Release.entitlements new file mode 100644 index 0000000000000..852fa1a4728ae --- /dev/null +++ b/dev/benchmarks/complex_layout/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index d68411a734cab..9d0c5438dead6 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,19 +28,19 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 integration_test: sdk: flutter - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +48,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,11 +70,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: ac89 +# PUBSPEC CHECKSUM: f88e diff --git a/dev/benchmarks/complex_layout/test/measure_scroll_smoothness.dart b/dev/benchmarks/complex_layout/test/measure_scroll_smoothness.dart index ef8d24552f55b..03aaa2f6c45a1 100644 --- a/dev/benchmarks/complex_layout/test/measure_scroll_smoothness.dart +++ b/dev/benchmarks/complex_layout/test/measure_scroll_smoothness.dart @@ -181,7 +181,7 @@ Future main() async { /// Calculates the smoothness measure from `scrollOffset` and `delays` list. /// -/// Smoothness (`abs_jerk`) is measured by the absolute value of the discrete +/// Smoothness (`abs_jerk`) is measured by the absolute value of the discrete /// 2nd derivative of the scroll offset. /// /// It was experimented that jerk (3rd derivative of the position) is a good diff --git a/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad.dart b/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad.dart new file mode 100644 index 0000000000000..41ccc9ff6942e --- /dev/null +++ b/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad.dart @@ -0,0 +1,11 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:complex_layout/main_bad.dart' as app; +import 'package:flutter_driver/driver_extension.dart'; + +void main() { + enableFlutterDriverExtension(); + app.main(); +} diff --git a/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad_test.dart b/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad_test.dart new file mode 100644 index 0000000000000..6778b55af7bc2 --- /dev/null +++ b/dev/benchmarks/complex_layout/test_driver/scroll_perf_bad_test.dart @@ -0,0 +1,59 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; + +void main() { + group('scrolling performance test', () { + late FlutterDriver driver; + + setUpAll(() async { + driver = await FlutterDriver.connect(); + + await driver.waitUntilFirstFrameRasterized(); + }); + + tearDownAll(() async { + if (driver != null) { + driver.close(); + } + }); + + Future testScrollPerf(String listKey, String summaryName) async { + // The slight initial delay avoids starting the timing during a + // period of increased load on the device. Without this delay, the + // benchmark has greater noise. + // See: https://github.com/flutter/flutter/issues/19434 + await Future.delayed(const Duration(milliseconds: 250)); + + final Timeline timeline = await driver.traceAction(() async { + // Find the scrollable stock list + final SerializableFinder list = find.byValueKey(listKey); + expect(list, isNotNull); + + // Scroll down + for (int i = 0; i < 5; i += 1) { + await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 500)); + } + + // Scroll up + for (int i = 0; i < 5; i += 1) { + await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 500)); + } + }); + + final TimelineSummary summary = TimelineSummary.summarize(timeline); + await summary.writeTimelineToFile(summaryName, pretty: true); + } + + test('complex_layout_scroll_perf', () async { + await testScrollPerf('complex-scroll-bad', 'complex_layout_scroll_perf'); + }, timeout: Timeout.none); + }); +} diff --git a/dev/benchmarks/complex_layout/test_memory/scroll_perf.dart b/dev/benchmarks/complex_layout/test_memory/scroll_perf.dart index 7e7426be9a53e..b06849c8a5f75 100644 --- a/dev/benchmarks/complex_layout/test_memory/scroll_perf.dart +++ b/dev/benchmarks/complex_layout/test_memory/scroll_perf.dart @@ -4,7 +4,7 @@ import 'dart:async'; -import 'package:complex_layout/main.dart'; +import 'package:complex_layout/src/app.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart index 7a1cf7363be08..0d07241dfd562 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_text_layout.dart @@ -401,9 +401,9 @@ class PaletteTabView extends StatelessWidget { Widget build(BuildContext context) { final TextTheme textTheme = Theme.of(context).textTheme; final TextStyle whiteTextStyle = - textTheme.bodyText2!.copyWith(color: Colors.white); + textTheme.bodyMedium!.copyWith(color: Colors.white); final TextStyle blackTextStyle = - textTheme.bodyText2!.copyWith(color: Colors.black); + textTheme.bodyMedium!.copyWith(color: Colors.black); return Scrollbar( child: ListView( itemExtent: kColorItemHeight, diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 9282ce455be9d..87762b8dea65d 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,7 +41,7 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_android: 6.0.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_ios: 6.0.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -50,21 +50,21 @@ dependencies: url_launcher_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_web: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 + test: 1.21.5 integration_test: sdk: flutter - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,10 +81,10 @@ dev_dependencies: shelf_web_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -219,4 +219,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 3170 +# PUBSPEC CHECKSUM: 6e75 diff --git a/dev/benchmarks/microbenchmarks/lib/foundation/platform_asset_bundle.dart b/dev/benchmarks/microbenchmarks/lib/foundation/platform_asset_bundle.dart index 41fb6cbe3d7f1..8d0ed1e7e750b 100644 --- a/dev/benchmarks/microbenchmarks/lib/foundation/platform_asset_bundle.dart +++ b/dev/benchmarks/microbenchmarks/lib/foundation/platform_asset_bundle.dart @@ -24,7 +24,7 @@ void main() async { watch.reset(); watch.start(); for (int i = 0; i < _kBatchSize; i += 1) { - // Note: We don't load images like this. PlatformAssetBundle is used for + // Note: We don't load images like this. PlatformAssetBundle is used for // other assets (like Rive animations). We are using an image because it's // conveniently sized and available for the test. tally += (await bundle.load('packages/flutter_gallery_assets/places/india_pondicherry_salt_farm.png')).lengthInBytes; diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 8460aa0ff7472..84bfaad3ba717 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.21.4 + test: 1.21.5 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,8 +27,8 @@ dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,14 +57,14 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -136,4 +136,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: d7cc +# PUBSPEC CHECKSUM: 6bd1 diff --git a/dev/benchmarks/multiple_flutters/module/lib/main.dart b/dev/benchmarks/multiple_flutters/module/lib/main.dart index 0036703d84535..48f340a175bec 100644 --- a/dev/benchmarks/multiple_flutters/module/lib/main.dart +++ b/dev/benchmarks/multiple_flutters/module/lib/main.dart @@ -106,7 +106,7 @@ class _MyHomePageState extends State { ), Text( '0', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), TextButton( onPressed: () {}, diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index cff3aede2099e..303716c790191 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: google_fonts: 3.0.1 # These are directly depended on so they can be pinned for https://github.com/flutter/flutter/issues/109397 path_provider: 2.0.11 - path_provider_android: 2.0.17 + path_provider_android: 2.0.20 path_provider_ios: 2.0.11 path_provider_linux: 2.1.7 path_provider_macos: 2.0.6 @@ -25,7 +25,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" ffi: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,9 +39,9 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 0.2.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 0.2.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -51,4 +51,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 18a0 +# PUBSPEC CHECKSUM: 8b9d diff --git a/dev/benchmarks/platform_channels_benchmarks/lib/main.dart b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart index b5850e1ae9e59..920721e22fdba 100644 --- a/dev/benchmarks/platform_channels_benchmarks/lib/main.dart +++ b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart @@ -8,7 +8,6 @@ import 'dart:math' as math; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - import 'package:microbenchmarks/common.dart'; List _makeTestBuffer(int size) { @@ -195,7 +194,7 @@ Future _runTests() async { ); /// WARNING: Don't change the following line of code, it will invalidate - /// `Large` tests. Instead make a different test. The size of largeBuffer + /// `Large` tests. Instead make a different test. The size of largeBuffer /// serialized is 14214 bytes. final List largeBuffer = _makeTestBuffer(1000); final ByteData largeBufferBytes = diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index dea1c52c6b3b6..911fd69951594 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,9 +28,9 @@ dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,15 +57,15 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.21.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.21.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -73,4 +73,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 74ba +# PUBSPEC CHECKSUM: 60bf diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 9462b1a4500ba..9e07eb9e763dd 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,17 +28,17 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,7 +46,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,11 +68,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: ac89 +# PUBSPEC CHECKSUM: f88e diff --git a/dev/benchmarks/platform_views_layout/test_driver/scroll_perf_test.dart b/dev/benchmarks/platform_views_layout/test_driver/scroll_perf_test.dart index 1fa81c6c6bba8..15002521b9e7f 100644 --- a/dev/benchmarks/platform_views_layout/test_driver/scroll_perf_test.dart +++ b/dev/benchmarks/platform_views_layout/test_driver/scroll_perf_test.dart @@ -33,16 +33,18 @@ void main() { final SerializableFinder list = find.byValueKey(listKey); expect(list, isNotNull); - // Scroll down - for (int i = 0; i < 5; i += 1) { - await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300)); - await Future.delayed(const Duration(milliseconds: 500)); - } - - // Scroll up - for (int i = 0; i < 5; i += 1) { - await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300)); - await Future.delayed(const Duration(milliseconds: 500)); + for (int j = 0; j < 5; j ++) { + // Scroll down + for (int i = 0; i < 5; i += 1) { + await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 500)); + } + + // Scroll up + for (int i = 0; i < 5; i += 1) { + await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300)); + await Future.delayed(const Duration(milliseconds: 500)); + } } }); diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 4d2d265312dc8..2b9fbdf798a1b 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,17 +28,17 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,7 +46,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,11 +68,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: ac89 +# PUBSPEC CHECKSUM: f88e diff --git a/dev/benchmarks/test_apps/stocks/lib/stock_symbol_viewer.dart b/dev/benchmarks/test_apps/stocks/lib/stock_symbol_viewer.dart index 3291f4d417176..16fb2f56cb359 100644 --- a/dev/benchmarks/test_apps/stocks/lib/stock_symbol_viewer.dart +++ b/dev/benchmarks/test_apps/stocks/lib/stock_symbol_viewer.dart @@ -25,7 +25,7 @@ class _StockSymbolView extends StatelessWidget { changeInPrice = '+$changeInPrice'; } - final TextStyle headings = Theme.of(context).textTheme.bodyText1!; + final TextStyle headings = Theme.of(context).textTheme.bodyLarge!; return Container( padding: const EdgeInsets.all(20.0), child: Column( @@ -37,7 +37,7 @@ class _StockSymbolView extends StatelessWidget { Text( stock.symbol, key: ValueKey('${stock.symbol}_symbol_name'), - style: Theme.of(context).textTheme.headline3, + style: Theme.of(context).textTheme.displaySmall, ), arrow, ], diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index a0da49d906f42..2a2a07336d725 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -24,17 +24,17 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,8 +42,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,16 +64,16 @@ dev_dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 22a8 +# PUBSPEC CHECKSUM: bfad diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index 5d4fb1466da09..1fce5f60ae707 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -443,7 +443,7 @@ class _SnippetChecker { /// The directory for the dart:ui code to be analyzed with the flutter code. /// - /// If this is null, then no dart:ui code is included in the analysis. It + /// If this is null, then no dart:ui code is included in the analysis. It /// defaults to the location inside of the flutter bin/cache directory that /// contains the dart:ui code supplied by the engine. final Directory? _dartUiLocation; diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart index fdd07a945aa66..b2cc416b457a8 100644 --- a/dev/bots/prepare_package.dart +++ b/dev/bots/prepare_package.dart @@ -185,7 +185,7 @@ typedef HttpReader = Future Function(Uri url, {Map he /// Creates a pre-populated Flutter archive from a git repo. class ArchiveCreator { - /// [tempDir] is the directory to use for creating the archive. The script + /// [tempDir] is the directory to use for creating the archive. The script /// will place several GiB of data there, so it should have available space. /// /// The processManager argument is used to inject a mock of [ProcessManager] for @@ -263,7 +263,7 @@ class ArchiveCreator { /// platform we're running on. final Platform platform; - /// The branch to build the archive for. The branch must contain [revision]. + /// The branch to build the archive for. The branch must contain [revision]. final Branch branch; /// The git revision hash to build the archive for. This revision has @@ -385,7 +385,7 @@ class ArchiveCreator { /// git will give an error. /// /// If [strict] is true, the exact [revision] must be tagged to return the - /// version. If [strict] is not true, will look backwards in time starting at + /// version. If [strict] is not true, will look backwards in time starting at /// [revision] to find the most recent version tag. /// /// The version found as a git tag is added to the information given by diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index c2a87d7fd7790..3dd8e48d10255 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -14,11 +14,11 @@ dependencies: path: 1.8.2 platform: 3.1.0 process: 4.2.4 - test: 1.21.4 + test: 1.21.5 _discoveryapis_commons: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,10 +26,10 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - equatable: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + equatable: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,13 +40,13 @@ dependencies: json_annotation: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + metrics_center: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pubspec_parse: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pubspec_parse: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,15 +58,15 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test_api: 0.4.12 + test_api: 0.4.13 -# PUBSPEC CHECKSUM: ecac +# PUBSPEC CHECKSUM: 0ab5 diff --git a/dev/bots/service_worker_test.dart b/dev/bots/service_worker_test.dart index e228c17c54f20..e0ec0aca50ca5 100644 --- a/dev/bots/service_worker_test.dart +++ b/dev/bots/service_worker_test.dart @@ -30,10 +30,16 @@ enum ServiceWorkerTestType { withFlutterJs, withFlutterJsShort, withFlutterJsEntrypointLoadedEvent, + + // Entrypoint generated by `flutter create`. + generatedEntrypoint, } // Run a web service worker test as a standalone Dart program. Future main() async { + // When updating this list, also update `dev/bots/test.dart`. This `main()` + // function is only here for convenience. Adding tests here will not add them + // to LUCI. await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withoutFlutterJs); await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withFlutterJs); await runWebServiceWorkerTest(headless: false, testType: ServiceWorkerTestType.withFlutterJsShort); @@ -42,13 +48,42 @@ Future main() async { await runWebServiceWorkerTestWithCachingResources(headless: false, testType: ServiceWorkerTestType.withFlutterJs); await runWebServiceWorkerTestWithCachingResources(headless: false, testType: ServiceWorkerTestType.withFlutterJsShort); await runWebServiceWorkerTestWithCachingResources(headless: false, testType: ServiceWorkerTestType.withFlutterJsEntrypointLoadedEvent); + await runWebServiceWorkerTestWithGeneratedEntrypoint(headless: false); await runWebServiceWorkerTestWithBlockedServiceWorkers(headless: false); + if (hasError) { print('One or more tests failed.'); reportErrorsAndExit(); } } +// Regression test for https://github.com/flutter/flutter/issues/109093. +// +// Tests the entrypoint that's generated by `flutter create`. +Future runWebServiceWorkerTestWithGeneratedEntrypoint({ + required bool headless, +}) async { + await _generateEntrypoint(); + await runWebServiceWorkerTestWithCachingResources(headless: headless, testType: ServiceWorkerTestType.generatedEntrypoint); +} + +Future _generateEntrypoint() async { + final Directory tempDirectory = Directory.systemTemp.createTempSync('flutter_web_generated_entrypoint.'); + await runCommand( + _flutter, + [ 'create', 'generated_entrypoint_test' ], + workingDirectory: tempDirectory.path, + ); + final File generatedEntrypoint = File(path.join(tempDirectory.path, 'generated_entrypoint_test', 'web', 'index.html')); + final String generatedEntrypointCode = generatedEntrypoint.readAsStringSync(); + final File testEntrypoint = File(path.join( + _testAppWebDirectory, + _testTypeToIndexFile(ServiceWorkerTestType.generatedEntrypoint), + )); + testEntrypoint.writeAsStringSync(generatedEntrypointCode); + tempDirectory.deleteSync(recursive: true); +} + Future _setAppVersion(int version) async { final File targetFile = File(_targetPath); await targetFile.writeAsString( @@ -77,6 +112,9 @@ String _testTypeToIndexFile(ServiceWorkerTestType type) { case ServiceWorkerTestType.withFlutterJsEntrypointLoadedEvent: indexFile = 'index_with_flutterjs_entrypoint_loaded.html'; break; + case ServiceWorkerTestType.generatedEntrypoint: + indexFile = 'generated_entrypoint.html'; + break; } return indexFile; } diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 098bca6497fb3..e7cd1c67c2ee2 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -186,7 +186,7 @@ const Map> kWebTestFileKnownFailures = _kAllBuildModes = ['debug', 'profile', 'release']; -// The seed used to shuffle tests. If not passed with +// The seed used to shuffle tests. If not passed with // --test-randomize-ordering-seed= on the command line, it will be set the // first time it is accessed. Pass zero to turn off shuffling. String? _shuffleSeed; @@ -1179,6 +1179,7 @@ Future _runWebLongRunningTests() async { () => runWebServiceWorkerTestWithCachingResources(headless: true, testType: ServiceWorkerTestType.withFlutterJs), () => runWebServiceWorkerTestWithCachingResources(headless: true, testType: ServiceWorkerTestType.withFlutterJsShort), () => runWebServiceWorkerTestWithCachingResources(headless: true, testType: ServiceWorkerTestType.withFlutterJsEntrypointLoadedEvent), + () => runWebServiceWorkerTestWithGeneratedEntrypoint(headless: true), () => runWebServiceWorkerTestWithBlockedServiceWorkers(headless: true), () => _runWebStackTraceTest('profile', 'lib/stack_trace.dart'), () => _runWebStackTraceTest('release', 'lib/stack_trace.dart'), diff --git a/dev/bots/unpublish_package.dart b/dev/bots/unpublish_package.dart index b8c79bc27b85e..61ede5a93f601 100644 --- a/dev/bots/unpublish_package.dart +++ b/dev/bots/unpublish_package.dart @@ -429,7 +429,7 @@ Future main(List rawArguments) async { 'confirm', help: 'If set, will actually remove the archive from Google Cloud Storage ' 'upon successful execution of this script. Published archives will be ' - 'removed from this directory: $baseUrl$releaseFolder. This option ' + 'removed from this directory: $baseUrl$releaseFolder. This option ' 'must be set to perform any action on the server, otherwise only a dry ' 'run is performed.', ); @@ -479,7 +479,7 @@ Future main(List rawArguments) async { } if (!(parsedArguments['confirm'] as bool)) { - _printBanner('This will be just a dry run. To actually perform the changes below, re-run with --confirm argument.'); + _printBanner('This will be just a dry run. To actually perform the changes below, re-run with --confirm argument.'); } final List channelArg = parsedArguments['channel'] as List; @@ -518,7 +518,7 @@ Future main(List rawArguments) async { errorExit('$message\n$stack', exitCode: exitCode); } if (!(parsedArguments['confirm'] as bool)) { - _printBanner('This was just a dry run. To actually perform the above changes, re-run with --confirm argument.'); + _printBanner('This was just a dry run. To actually perform the above changes, re-run with --confirm argument.'); } exit(0); } diff --git a/dev/ci/docker_linux/Dockerfile b/dev/ci/docker_linux/Dockerfile index 127e67fc13290..f3f328f6aba4e 100644 --- a/dev/ci/docker_linux/Dockerfile +++ b/dev/ci/docker_linux/Dockerfile @@ -12,7 +12,7 @@ # Last manual update 2021-09-24 (changing this comment will re-build image) -FROM debian@sha256:f6957458017ec31c4e325a76f39d6323c4c21b0e31572efa006baa927a160891 +FROM ubuntu:bionic@sha256:e4771b7160543c6e43968b4e9795be9ddcad9d573edd7cd7aebd3ce61326fc7a MAINTAINER Flutter Developers RUN apt-get update -y && \ diff --git a/dev/conductor/core/lib/src/start.dart b/dev/conductor/core/lib/src/start.dart index 41cb9077d854d..c02bc1615e0d4 100644 --- a/dev/conductor/core/lib/src/start.dart +++ b/dev/conductor/core/lib/src/start.dart @@ -134,13 +134,13 @@ class StartCommand extends Command { platform.environment, )!; final String frameworkMirror = - 'https://github.com/$githubUsername/flutter.git'; + 'git@github.com:$githubUsername/flutter.git'; final String engineUpstream = getValueFromEnvOrArgs( kEngineUpstreamOption, argumentResults, platform.environment, )!; - final String engineMirror = 'https://github.com/$githubUsername/engine.git'; + final String engineMirror = 'git@github.com:$githubUsername/engine.git'; final String candidateBranch = getValueFromEnvOrArgs( kCandidateOption, argumentResults, diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index ade5db560b01f..672102f5e448e 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,15 +31,15 @@ dependencies: typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 - test_api: 0.4.12 + test: 1.21.5 + test_api: 0.4.13 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,10 +59,10 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d7b2 +# PUBSPEC CHECKSUM: 84b6 diff --git a/dev/conductor/core/test/start_test.dart b/dev/conductor/core/test/start_test.dart index f347cfb666b1f..7939b5614b726 100644 --- a/dev/conductor/core/test/start_test.dart +++ b/dev/conductor/core/test/start_test.dart @@ -24,8 +24,8 @@ void main() { const String checkoutsParentDirectory = '$flutterRoot/dev/tools/'; const String githubUsername = 'user'; const String frameworkMirror = - 'https://github.com/$githubUsername/flutter.git'; - const String engineMirror = 'https://github.com/$githubUsername/engine.git'; + 'git@github.com:$githubUsername/flutter.git'; + const String engineMirror = 'git@github.com:$githubUsername/engine.git'; const String candidateBranch = 'flutter-1.2-candidate.3'; const String releaseChannel = 'beta'; const String revision = 'abcd1234'; diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 250d9429cc180..f0c2bbdbcb1a2 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -12,21 +12,21 @@ dependencies: async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,13 +46,13 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4304 +# PUBSPEC CHECKSUM: 3908 diff --git a/dev/devicelab/bin/tasks/animated_complex_opacity_perf_impeller_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/animated_complex_opacity_perf_impeller_ios__e2e_summary.dart new file mode 100644 index 0000000000000..71eacabfff502 --- /dev/null +++ b/dev/devicelab/bin/tasks/animated_complex_opacity_perf_impeller_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createAnimatedComplexOpacityPerfE2ETest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__e2e_summary.dart b/dev/devicelab/bin/tasks/animated_complex_opacity_perf_ios__e2e_summary.dart similarity index 77% rename from dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__e2e_summary.dart rename to dev/devicelab/bin/tasks/animated_complex_opacity_perf_ios__e2e_summary.dart index 38d83b1e216ee..d80f07f5f8627 100644 --- a/dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__e2e_summary.dart +++ b/dev/devicelab/bin/tasks/animated_complex_opacity_perf_ios__e2e_summary.dart @@ -9,6 +9,6 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createCubicBezierPerfSkSlWarmupE2ETest()); + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createAnimatedComplexOpacityPerfE2ETest()); } diff --git a/dev/devicelab/bin/tasks/backdrop_filter_perf_impeller_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/backdrop_filter_perf_impeller_ios__timeline_summary.dart new file mode 100644 index 0000000000000..52ad4ac02435b --- /dev/null +++ b/dev/devicelab/bin/tasks/backdrop_filter_perf_impeller_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createBackdropFilterPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__timeline_summary.dart b/dev/devicelab/bin/tasks/basic_material_app_macos__compile.dart similarity index 77% rename from dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__timeline_summary.dart rename to dev/devicelab/bin/tasks/basic_material_app_macos__compile.dart index 83eb00361c383..b97ba87c82643 100644 --- a/dev/devicelab/bin/tasks/cubic_bezier_perf_sksl_warmup__timeline_summary.dart +++ b/dev/devicelab/bin/tasks/basic_material_app_macos__compile.dart @@ -7,6 +7,6 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createCubicBezierPerfSkSLWarmupTest()); + deviceOperatingSystem = DeviceOperatingSystem.macos; + await task(createBasicMaterialCompileTest()); } diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart index f2185c1bca8a3..706ae3fd51119 100644 --- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart +++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart @@ -101,28 +101,14 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals final String outputPath = path.join(projectDir.path, outputDirectoryName); - // TODO(jmagman): Remove ios-arm64_armv7 checks when armv7 engine artifacts are removed. - final String arm64FlutterFramework = path.join( + checkFileExists(path.join( outputPath, 'Debug', 'Flutter.xcframework', 'ios-arm64', 'Flutter.framework', - ); - - final String armv7FlutterFramework = path.join( - outputPath, - 'Debug', - 'Flutter.xcframework', - 'ios-arm64_armv7', - 'Flutter.framework', - ); - - final bool arm64FlutterBinaryExists = exists(File(path.join(arm64FlutterFramework, 'Flutter'))); - final bool armv7FlutterBinaryExists = exists(File(path.join(armv7FlutterFramework, 'Flutter'))); - if (!arm64FlutterBinaryExists && !armv7FlutterBinaryExists) { - throw TaskResult.failure('Expected debug Flutter engine artifact binary to exist'); - } + 'Flutter', + )); final String debugAppFrameworkPath = path.join( outputPath, @@ -203,6 +189,23 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'vm_snapshot_data', )); + final String appFrameworkDsymPath = path.join( + outputPath, + mode, + 'App.xcframework', + 'ios-arm64', + 'dSYMs', + 'App.framework.dSYM' + ); + checkDirectoryExists(appFrameworkDsymPath); + await _checkDsym(path.join( + appFrameworkDsymPath, + 'Contents', + 'Resources', + 'DWARF', + 'App', + )); + checkFileExists(path.join( outputPath, mode, @@ -225,8 +228,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals section("Check all modes' engine dylib"); for (final String mode in ['Debug', 'Profile', 'Release']) { - // TODO(jmagman): Remove ios-arm64_armv7 checks when armv7 engine artifacts are removed. - final String arm64EngineBinary = path.join( + final String engineBinary = path.join( outputPath, mode, 'Flutter.xcframework', @@ -234,23 +236,7 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'Flutter.framework', 'Flutter', ); - - final String arm64Armv7EngineBinary = path.join( - outputPath, - mode, - 'Flutter.xcframework', - 'ios-arm64_armv7', - 'Flutter.framework', - 'Flutter', - ); - - if (exists(File(arm64EngineBinary))) { - await _checkBitcode(arm64EngineBinary, mode); - } else if (exists(File(arm64Armv7EngineBinary))) { - await _checkBitcode(arm64Armv7EngineBinary, mode); - } else { - throw TaskResult.failure('Expected Flutter $mode engine artifact binary to exist'); - } + await _checkBitcode(engineBinary, mode); checkFileExists(path.join( outputPath, @@ -285,12 +271,21 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals ); await _checkDylib(pluginFrameworkPath); - await _checkBitcode(pluginFrameworkPath, mode); if (!await _linksOnFlutter(pluginFrameworkPath)) { throw TaskResult.failure('$pluginFrameworkPath does not link on Flutter'); } + // TODO(jmagman): Remove ios-arm64_armv7 checks when CI is updated to Xcode 14. final String transitiveDependencyFrameworkPath = path.join( + outputPath, + mode, + 'Reachability.xcframework', + 'ios-arm64', + 'Reachability.framework', + 'Reachability', + ); + + final String armv7TransitiveDependencyFrameworkPath = path.join( outputPath, mode, 'Reachability.xcframework', @@ -298,8 +293,17 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'Reachability.framework', 'Reachability', ); - if (await _linksOnFlutter(transitiveDependencyFrameworkPath)) { - throw TaskResult.failure('Transitive dependency $transitiveDependencyFrameworkPath unexpectedly links on Flutter'); + + final bool transitiveDependencyExists = exists(File(transitiveDependencyFrameworkPath)); + final bool armv7TransitiveDependencyExists = exists(File(armv7TransitiveDependencyFrameworkPath)); + if (!transitiveDependencyExists && !armv7TransitiveDependencyExists) { + throw TaskResult.failure('Expected debug Flutter engine artifact binary to exist'); + } + + if ((transitiveDependencyExists && await _linksOnFlutter(transitiveDependencyFrameworkPath)) || + (armv7TransitiveDependencyExists && await _linksOnFlutter(armv7TransitiveDependencyFrameworkPath))) { + throw TaskResult.failure( + 'Transitive dependency $transitiveDependencyFrameworkPath unexpectedly links on Flutter'); } checkFileExists(path.join( @@ -346,14 +350,6 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals checkFileExists(simulatorFrameworkHeaderPath); } - checkDirectoryExists(path.join( - outputPath, - 'Release', - 'connectivity.xcframework', - 'ios-arm64', - 'BCSymbolMaps', - )); - section('Check all modes have generated plugin registrant'); for (final String mode in ['Debug', 'Profile', 'Release']) { @@ -369,7 +365,6 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'FlutterPluginRegistrant', ); await _checkStatic(registrantFrameworkPath); - await _checkBitcode(registrantFrameworkPath, mode); checkFileExists(path.join( outputPath, @@ -426,6 +421,25 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals 'App', )); + if (mode != 'Debug') { + final String appFrameworkDsymPath = path.join( + cocoapodsOutputPath, + mode, + 'App.xcframework', + 'ios-arm64', + 'dSYMs', + 'App.framework.dSYM' + ); + checkDirectoryExists(appFrameworkDsymPath); + await _checkDsym(path.join( + appFrameworkDsymPath, + 'Contents', + 'Resources', + 'DWARF', + 'App', + )); + } + if (Directory(path.join( cocoapodsOutputPath, mode, @@ -604,6 +618,23 @@ Future _testBuildMacOSFramework(Directory projectDir) async { 'Resources', 'Info.plist', )); + + final String appFrameworkDsymPath = path.join( + outputPath, + mode, + 'App.xcframework', + 'macos-arm64_x86_64', + 'dSYMs', + 'App.framework.dSYM' + ); + checkDirectoryExists(appFrameworkDsymPath); + await _checkDsym(path.join( + appFrameworkDsymPath, + 'Contents', + 'Resources', + 'DWARF', + 'App', + )); } section("Check all modes' engine dylib"); @@ -734,6 +765,25 @@ Future _testBuildMacOSFramework(Directory projectDir) async { 'App', )); + if (mode != 'Debug') { + final String appFrameworkDsymPath = path.join( + cocoapodsOutputPath, + mode, + 'App.xcframework', + 'macos-arm64_x86_64', + 'dSYMs', + 'App.framework.dSYM' + ); + checkDirectoryExists(appFrameworkDsymPath); + await _checkDsym(path.join( + appFrameworkDsymPath, + 'Contents', + 'Resources', + 'DWARF', + 'App', + )); + } + await _checkStatic(path.join( cocoapodsOutputPath, mode, @@ -772,6 +822,13 @@ Future _checkDylib(String pathToLibrary) async { } } +Future _checkDsym(String pathToSymbolFile) async { + final String binaryFileType = await fileType(pathToSymbolFile); + if (!binaryFileType.contains('dSYM companion file')) { + throw TaskResult.failure('$pathToSymbolFile is not a dSYM, found: $binaryFileType'); + } +} + Future _checkStatic(String pathToLibrary) async { final String binaryFileType = await fileType(pathToLibrary); if (!binaryFileType.contains('current ar archive random library')) { diff --git a/dev/devicelab/bin/tasks/color_filter_and_fade_perf_impeller_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/color_filter_and_fade_perf_impeller_ios__e2e_summary.dart new file mode 100644 index 0000000000000..682b1e3bc0e56 --- /dev/null +++ b/dev/devicelab/bin/tasks/color_filter_and_fade_perf_impeller_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createColorFilterAndFadePerfE2ETest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/color_filter_and_fade_perf_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/color_filter_and_fade_perf_ios__e2e_summary.dart new file mode 100644 index 0000000000000..1316e698ae22c --- /dev/null +++ b/dev/devicelab/bin/tasks/color_filter_and_fade_perf_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createColorFilterAndFadePerfE2ETest()); +} diff --git a/dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf_e2e.dart b/dev/devicelab/bin/tasks/complex_layout_macos__compile.dart similarity index 74% rename from dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf_e2e.dart rename to dev/devicelab/bin/tasks/complex_layout_macos__compile.dart index 4baec122dbfc2..959d4335db3b1 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf_e2e.dart +++ b/dev/devicelab/bin/tasks/complex_layout_macos__compile.dart @@ -7,6 +7,6 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createFlutterGalleryTransitionsPerfSkSLWarmupE2ETest()); + deviceOperatingSystem = DeviceOperatingSystem.macos; + await task(createComplexLayoutCompileTest()); } diff --git a/dev/devicelab/bin/tasks/complex_layout_macos__start_up.dart b/dev/devicelab/bin/tasks/complex_layout_macos__start_up.dart new file mode 100644 index 0000000000000..4c975cad838b2 --- /dev/null +++ b/dev/devicelab/bin/tasks/complex_layout_macos__start_up.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.macos; + await task(createComplexLayoutStartupTest()); +} diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_impeller_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_impeller_ios__timeline_summary.dart new file mode 100644 index 0000000000000..996d04b728ee7 --- /dev/null +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_impeller_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createComplexLayoutScrollPerfTest(badScroll: true, enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart new file mode 100644 index 0000000000000..640441e12b564 --- /dev/null +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createComplexLayoutScrollPerfTest(badScroll: true)); +} diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller_ios__timeline_summary.dart new file mode 100644 index 0000000000000..53578a3df05d3 --- /dev/null +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf_impeller_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createComplexLayoutScrollPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_impeller_ios.dart similarity index 86% rename from dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart rename to dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_impeller_ios.dart index 4b16f5dd212aa..859025ea6e9cf 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery_ios__transition_perf.dart +++ b/dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_impeller_ios.dart @@ -8,5 +8,5 @@ import 'package:flutter_devicelab/tasks/gallery.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.ios; - await task(createGalleryTransitionTest()); + await task(createGalleryTransitionE2ETest(enableImpeller: true)); } diff --git a/dev/devicelab/bin/tasks/flutter_gallery_macos__compile.dart b/dev/devicelab/bin/tasks/flutter_gallery_macos__compile.dart new file mode 100644 index 0000000000000..2666691f57c80 --- /dev/null +++ b/dev/devicelab/bin/tasks/flutter_gallery_macos__compile.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.macos; + await task(createFlutterGalleryCompileTest()); +} diff --git a/dev/devicelab/bin/tasks/fullscreen_textfield_perf_impeller_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/fullscreen_textfield_perf_impeller_ios__e2e_summary.dart new file mode 100644 index 0000000000000..5972a38f77460 --- /dev/null +++ b/dev/devicelab/bin/tasks/fullscreen_textfield_perf_impeller_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createFullscreenTextfieldPerfE2ETest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/fullscreen_textfield_perf_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/fullscreen_textfield_perf_ios__e2e_summary.dart new file mode 100644 index 0000000000000..c3316d1d7b24d --- /dev/null +++ b/dev/devicelab/bin/tasks/fullscreen_textfield_perf_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createFullscreenTextfieldPerfE2ETest()); +} diff --git a/dev/devicelab/bin/tasks/hello_world_macos__compile.dart b/dev/devicelab/bin/tasks/hello_world_macos__compile.dart new file mode 100644 index 0000000000000..ce741eca5cbee --- /dev/null +++ b/dev/devicelab/bin/tasks/hello_world_macos__compile.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.macos; + await task(createHelloWorldCompileTest()); +} diff --git a/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_impeller_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_impeller_ios__timeline_summary.dart new file mode 100644 index 0000000000000..51586c08dc1d2 --- /dev/null +++ b/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_impeller_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createImageFilteredTransformAnimationPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart b/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_ios__timeline_summary.dart similarity index 87% rename from dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart rename to dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_ios__timeline_summary.dart index 4e5e0e57c5fd6..c78cfe77fbcad 100644 --- a/dev/devicelab/bin/tasks/cubic_bezier_perf_ios_sksl_warmup__timeline_summary.dart +++ b/dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_ios__timeline_summary.dart @@ -8,5 +8,5 @@ import 'package:flutter_devicelab/tasks/perf_tests.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.ios; - await task(createCubicBezierPerfSkSLWarmupTest()); + await task(createImageFilteredTransformAnimationPerfTest()); } diff --git a/dev/devicelab/bin/tasks/microbenchmarks_impeller_ios.dart b/dev/devicelab/bin/tasks/microbenchmarks_impeller_ios.dart new file mode 100644 index 0000000000000..3daa6d791ff04 --- /dev/null +++ b/dev/devicelab/bin/tasks/microbenchmarks_impeller_ios.dart @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/microbenchmarks.dart'; + +/// Runs microbenchmarks on iOS. +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createMicrobenchmarkTask(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 47b17302fe0dd..54d883d4d0918 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -421,7 +421,6 @@ end if ((await fileType(builtFlutterBinary)).contains('armv7')) { throw TaskResult.failure('Unexpected armv7 architecture slice in $builtFlutterBinary'); } - await checkContainsBitcode(builtFlutterBinary); final String builtAppBinary = path.join( archivedAppPath, @@ -433,7 +432,6 @@ end if ((await fileType(builtAppBinary)).contains('armv7')) { throw TaskResult.failure('Unexpected armv7 architecture slice in $builtAppBinary'); } - await checkContainsBitcode(builtAppBinary); // The host app example builds plugins statically, url_launcher_ios.framework // should not exist. @@ -442,6 +440,16 @@ end 'Frameworks', 'url_launcher_ios.framework', )); + + checkFileExists(path.join( + '${objectiveCBuildArchiveDirectory.path}.xcarchive', + 'dSYMs', + 'App.framework.dSYM', + 'Contents', + 'Resources', + 'DWARF', + 'App' + )); }); section('Run platform unit tests'); diff --git a/dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf.dart b/dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart similarity index 75% rename from dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf.dart rename to dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart index 42e32ea97d718..2b8106f001e20 100644 --- a/dev/devicelab/bin/tasks/flutter_gallery_sksl_warmup__transition_perf.dart +++ b/dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart @@ -7,6 +7,6 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/tasks/perf_tests.dart'; Future main() async { - deviceOperatingSystem = DeviceOperatingSystem.android; - await task(createFlutterGalleryTransitionsPerfSkSLWarmupTest()); + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createUiKitViewScrollPerfTest(enableImpeller: true)); } diff --git a/dev/devicelab/bin/tasks/simple_animation_perf_impeller_ios.dart b/dev/devicelab/bin/tasks/simple_animation_perf_impeller_ios.dart new file mode 100644 index 0000000000000..9f6a37929f688 --- /dev/null +++ b/dev/devicelab/bin/tasks/simple_animation_perf_impeller_ios.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createSimpleAnimationPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/tiles_scroll_perf_impeller_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/tiles_scroll_perf_impeller_ios__timeline_summary.dart new file mode 100644 index 0000000000000..361df86db5061 --- /dev/null +++ b/dev/devicelab/bin/tasks/tiles_scroll_perf_impeller_ios__timeline_summary.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createTilesScrollPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/windows_startup_test.dart b/dev/devicelab/bin/tasks/windows_startup_test.dart new file mode 100644 index 0000000000000..d74c6621c7dc1 --- /dev/null +++ b/dev/devicelab/bin/tasks/windows_startup_test.dart @@ -0,0 +1,12 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.windows; + await task(createWindowsStartupDriverTest(deviceIdOverride: 'windows')); +} diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart index 275781247a69a..2a384edbe25fe 100644 --- a/dev/devicelab/lib/framework/ios.dart +++ b/dev/devicelab/lib/framework/ios.dart @@ -8,7 +8,6 @@ import 'dart:io'; import 'package:path/path.dart' as path; import 'host_agent.dart'; -import 'task_result.dart'; import 'utils.dart'; typedef SimulatorFunction = Future Function(String deviceId); @@ -85,12 +84,6 @@ Future containsBitcode(String pathToBinary) async { return !emptyBitcodeMarkerFound; } -Future checkContainsBitcode(String pathToBinary) async { - if (!await containsBitcode(pathToBinary)) { - throw TaskResult.failure('Expected bitcode in $pathToBinary'); - } -} - /// Creates and boots a new simulator, passes the new simulator's identifier to /// `testFunction`. /// diff --git a/dev/devicelab/lib/tasks/build_test_task.dart b/dev/devicelab/lib/tasks/build_test_task.dart index 14840078c2285..2405763fd1472 100644 --- a/dev/devicelab/lib/tasks/build_test_task.dart +++ b/dev/devicelab/lib/tasks/build_test_task.dart @@ -59,6 +59,7 @@ abstract class BuildTestTask { } section('BUILDING APPLICATION'); await flutter('build', options: getBuildArgs(deviceOperatingSystem)); + copyArtifacts(); }); } @@ -83,6 +84,11 @@ abstract class BuildTestTask { /// Args passed to flutter drive to test the built application. List getTestArgs(DeviceOperatingSystem deviceOperatingSystem, String deviceId) => throw UnimplementedError('getTestArgs is not implemented'); + /// Copy artifacts to [applicationBinaryPath] if specified. + /// + /// This is needed when running from CI, so that LUCI recipes know where to locate and upload artifacts to GCS. + void copyArtifacts() => throw UnimplementedError('copyArtifacts is not implemented'); + /// Logic to construct [TaskResult] from this test's results. Future parseTaskResult() => throw UnimplementedError('parseTaskResult is not implemented'); @@ -100,10 +106,6 @@ abstract class BuildTestTask { throw Exception('Both build and test should not be passed. Pass only one.'); } - if (buildOnly && applicationBinaryPath != null) { - throw Exception('Application binary path is only used for tests'); - } - if (!testOnly) { await build(); } diff --git a/dev/devicelab/lib/tasks/gallery.dart b/dev/devicelab/lib/tasks/gallery.dart index 4c24622cbb8f4..4ce08ab82e354 100644 --- a/dev/devicelab/lib/tasks/gallery.dart +++ b/dev/devicelab/lib/tasks/gallery.dart @@ -25,7 +25,10 @@ TaskFunction createGalleryTransitionTest({bool semanticsEnabled = false}) { return GalleryTransitionTest(semanticsEnabled: semanticsEnabled); } -TaskFunction createGalleryTransitionE2ETest({bool semanticsEnabled = false}) { +TaskFunction createGalleryTransitionE2ETest({ + bool semanticsEnabled = false, + bool enableImpeller = false, +}) { return GalleryTransitionTest( testFile: semanticsEnabled ? 'transitions_perf_e2e_with_semantics' @@ -35,6 +38,7 @@ TaskFunction createGalleryTransitionE2ETest({bool semanticsEnabled = false}) { transitionDurationFile: null, timelineTraceFile: null, driverFile: 'transitions_perf_e2e_test', + enableImpeller: enableImpeller, ); } @@ -59,12 +63,14 @@ class GalleryTransitionTest { this.driverFile, this.measureCpuGpu = true, this.measureMemory = true, + this.enableImpeller = false, }); final bool semanticsEnabled; final bool needFullTimeline; final bool measureCpuGpu; final bool measureMemory; + final bool enableImpeller; final String testFile; final String timelineSummaryFile; final String? timelineTraceFile; @@ -102,6 +108,7 @@ class GalleryTransitionTest { await flutter('drive', options: [ '--no-dds', '--profile', + if (enableImpeller) '--enable-impeller', if (needFullTimeline) '--trace-startup', if (applicationBinaryPath != null) @@ -212,6 +219,16 @@ class GalleryTransitionBuildTest extends BuildTestTask { final String testOutputDirectory = Platform.environment['FLUTTER_TEST_OUTPUTS_DIR'] ?? '${galleryDirectory.path}/build'; + @override + void copyArtifacts() { + if(applicationBinaryPath != null) { + copy( + file('${galleryDirectory.path}/build/app/outputs/flutter-apk/app-profile.apk'), + Directory(applicationBinaryPath!), + ); + } + } + @override List getBuildArgs(DeviceOperatingSystem deviceOperatingSystem) { return [ @@ -310,7 +327,7 @@ class GalleryTransitionBuildTest extends BuildTestTask { @override String getApplicationBinaryPath() { if (applicationBinaryPath != null) { - return applicationBinaryPath!; + return '${applicationBinaryPath!}/app-profile.apk'; } return 'build/app/outputs/flutter-apk/app-profile.apk'; diff --git a/dev/devicelab/lib/tasks/integration_tests.dart b/dev/devicelab/lib/tasks/integration_tests.dart index 87d114ac38b68..6e5df519ec5ef 100644 --- a/dev/devicelab/lib/tasks/integration_tests.dart +++ b/dev/devicelab/lib/tasks/integration_tests.dart @@ -149,6 +149,14 @@ TaskFunction createSpellCheckIntegrationTest() { ); } +TaskFunction createWindowsStartupDriverTest({String? deviceIdOverride}) { + return DriverTest( + '${flutterDirectory.path}/dev/integration_tests/windows_startup_test', + 'lib/main.dart', + deviceIdOverride: deviceIdOverride, + ); +} + class DriverTest { DriverTest( this.testDirectory, diff --git a/dev/devicelab/lib/tasks/microbenchmarks.dart b/dev/devicelab/lib/tasks/microbenchmarks.dart index c707919a9477f..c80e916c1aaf7 100644 --- a/dev/devicelab/lib/tasks/microbenchmarks.dart +++ b/dev/devicelab/lib/tasks/microbenchmarks.dart @@ -15,7 +15,7 @@ import '../microbenchmarks.dart'; /// Creates a device lab task that runs benchmarks in /// `dev/benchmarks/microbenchmarks` reports results to the dashboard. -TaskFunction createMicrobenchmarkTask() { +TaskFunction createMicrobenchmarkTask({bool enableImpeller = false}) { return () async { final Device device = await devices.workingDevice; await device.unlock(); @@ -32,6 +32,7 @@ TaskFunction createMicrobenchmarkTask() { // --release doesn't work on iOS due to code signing issues '--profile', '--no-publish-port', + if (enableImpeller) '--enable-impeller', '-d', device.deviceId, ]; diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 84eb00020d5cc..85d8368a19614 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -23,30 +23,39 @@ String _testOutputDirectory(String testDirectory) { return Platform.environment['FLUTTER_TEST_OUTPUTS_DIR'] ?? '$testDirectory/build'; } -TaskFunction createComplexLayoutScrollPerfTest({bool measureCpuGpu = true}) { +TaskFunction createComplexLayoutScrollPerfTest({ + bool measureCpuGpu = true, + bool badScroll = false, + bool enableImpeller = false, +}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/complex_layout', - 'test_driver/scroll_perf.dart', + badScroll + ? 'test_driver/scroll_perf_bad.dart' + : 'test_driver/scroll_perf.dart', 'complex_layout_scroll_perf', measureCpuGpu: measureCpuGpu, + enableImpeller: enableImpeller, ).run; } -TaskFunction createTilesScrollPerfTest() { +TaskFunction createTilesScrollPerfTest({bool enableImpeller = false}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/complex_layout', 'test_driver/scroll_perf.dart', 'tiles_scroll_perf', + enableImpeller: enableImpeller, ).run; } -TaskFunction createUiKitViewScrollPerfTest() { +TaskFunction createUiKitViewScrollPerfTest({bool enableImpeller = false}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/platform_views_layout', 'test_driver/uikit_view_scroll_perf.dart', 'platform_views_scroll_perf', testDriver: 'test_driver/scroll_perf_test.dart', needsFullTimeline: false, + enableImpeller: enableImpeller, ).run; } @@ -108,22 +117,6 @@ TaskFunction createCubicBezierPerfE2ETest() { ).run; } -TaskFunction createCubicBezierPerfSkSlWarmupE2ETest() { - return PerfTestWithSkSL.e2e( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test/cubic_bezier_perf_e2e.dart', - ).run; -} - -TaskFunction createCubicBezierPerfSkSLWarmupTest() { - return PerfTestWithSkSL( - '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', - 'test_driver/run_app.dart', - 'cubic_bezier_perf', - testDriver: 'test_driver/cubic_bezier_perf_test.dart', - ).run; -} - TaskFunction createFlutterGalleryTransitionsPerfSkSLWarmupTest() { return PerfTestWithSkSL( '${flutterDirectory.path}/dev/integration_tests/flutter_gallery', @@ -132,15 +125,10 @@ TaskFunction createFlutterGalleryTransitionsPerfSkSLWarmupTest() { ).run; } -TaskFunction createFlutterGalleryTransitionsPerfSkSLWarmupE2ETest() { - return PerfTestWithSkSL.e2e( - '${flutterDirectory.path}/dev/integration_tests/flutter_gallery', - 'test_driver/transitions_perf_e2e.dart', - testDriver: 'test_driver/transitions_perf_e2e_test.dart', - ).run; -} - -TaskFunction createBackdropFilterPerfTest({bool measureCpuGpu = true}) { +TaskFunction createBackdropFilterPerfTest({ + bool measureCpuGpu = true, + bool enableImpeller = false, +}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test_driver/run_app.dart', @@ -148,6 +136,7 @@ TaskFunction createBackdropFilterPerfTest({bool measureCpuGpu = true}) { measureCpuGpu: measureCpuGpu, testDriver: 'test_driver/backdrop_filter_perf_test.dart', saveTraceFile: true, + enableImpeller: enableImpeller, ).run; } @@ -180,7 +169,10 @@ TaskFunction createPostBackdropFilterPerfTest({bool measureCpuGpu = true}) { ).run; } -TaskFunction createSimpleAnimationPerfTest({bool measureCpuGpu = true}) { +TaskFunction createSimpleAnimationPerfTest({ + bool measureCpuGpu = true, + bool enableImpeller = false, +}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test_driver/run_app.dart', @@ -188,6 +180,7 @@ TaskFunction createSimpleAnimationPerfTest({bool measureCpuGpu = true}) { measureCpuGpu: measureCpuGpu, testDriver: 'test_driver/simple_animation_perf_test.dart', saveTraceFile: true, + enableImpeller: enableImpeller, ).run; } @@ -358,10 +351,13 @@ TaskFunction createFullscreenTextfieldPerfTest() { ).run; } -TaskFunction createFullscreenTextfieldPerfE2ETest() { +TaskFunction createFullscreenTextfieldPerfE2ETest({ + bool enableImpeller = false, +}) { return PerfTest.e2e( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test/fullscreen_textfield_perf_e2e.dart', + enableImpeller: enableImpeller, ).run; } @@ -382,10 +378,11 @@ TaskFunction createColorFilterAndFadePerfTest() { ).run; } -TaskFunction createColorFilterAndFadePerfE2ETest() { +TaskFunction createColorFilterAndFadePerfE2ETest({bool enableImpeller = false}) { return PerfTest.e2e( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test/color_filter_and_fade_perf_e2e.dart', + enableImpeller: enableImpeller, ).run; } @@ -427,13 +424,16 @@ TaskFunction createFadingChildAnimationPerfTest() { ).run; } -TaskFunction createImageFilteredTransformAnimationPerfTest() { +TaskFunction createImageFilteredTransformAnimationPerfTest({ + bool enableImpeller = false, +}) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test_driver/run_app.dart', 'imagefiltered_transform_animation_perf', testDriver: 'test_driver/imagefiltered_transform_animation_perf_test.dart', saveTraceFile: true, + enableImpeller: enableImpeller, ).run; } @@ -617,10 +617,13 @@ TaskFunction createGradientStaticPerfE2ETest() { ).run; } -TaskFunction createAnimatedComplexOpacityPerfE2ETest() { +TaskFunction createAnimatedComplexOpacityPerfE2ETest({ + bool enableImpeller = false, +}) { return PerfTest.e2e( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test/animated_complex_opacity_perf_e2e.dart', + enableImpeller: enableImpeller, ).run; } @@ -688,18 +691,19 @@ class StartupTest { ]); applicationBinaryPath = '$testDirectory/build/app/outputs/flutter-apk/app-profile.apk'; break; + case DeviceOperatingSystem.fake: + case DeviceOperatingSystem.fuchsia: + break; case DeviceOperatingSystem.ios: + case DeviceOperatingSystem.macos: await flutter('build', options: [ - 'ios', + if (deviceOperatingSystem == DeviceOperatingSystem.ios) 'ios' else 'macos', '-v', '--profile', '--target=$target', ]); - applicationBinaryPath = _findIosAppInBuildDirectory('$testDirectory/build/ios/iphoneos'); - break; - case DeviceOperatingSystem.fake: - case DeviceOperatingSystem.fuchsia: - case DeviceOperatingSystem.macos: + final String buildRoot = path.join(testDirectory, 'build'); + applicationBinaryPath = _findDarwinAppInBuildDirectory(buildRoot); break; case DeviceOperatingSystem.windows: await flutter('build', options: [ @@ -829,7 +833,7 @@ class DevtoolsStartupTest { '-v', '--profile', ]); - applicationBinaryPath = _findIosAppInBuildDirectory('$testDirectory/build/ios/iphoneos'); + applicationBinaryPath = _findDarwinAppInBuildDirectory('$testDirectory/build/ios/iphoneos'); break; case DeviceOperatingSystem.fake: case DeviceOperatingSystem.fuchsia: @@ -1400,28 +1404,42 @@ class CompileTest { switch (deviceOperatingSystem) { case DeviceOperatingSystem.ios: - options.insert(0, 'ios'); + case DeviceOperatingSystem.macos: + unawaited(stderr.flush()); + late final String deviceId; + if (deviceOperatingSystem == DeviceOperatingSystem.ios) { + deviceId = 'ios'; + } else if (deviceOperatingSystem == DeviceOperatingSystem.macos) { + deviceId = 'macos'; + } else { + throw Exception('Attempted to run darwin compile workflow with $deviceOperatingSystem'); + } + + options.insert(0, deviceId); options.add('--tree-shake-icons'); options.add('--split-debug-info=infos/'); watch.start(); await flutter('build', options: options); watch.stop(); - final Directory appBuildDirectory = dir(path.join(cwd, 'build/ios/Release-iphoneos')); - final Directory? appBundle = appBuildDirectory - .listSync() - .whereType() - .singleWhere((Directory? directory) => - directory != null && path.extension(directory.path) == '.app', - orElse: () => null); - if (appBundle == null) { - throw 'Failed to find app bundle in ${appBuildDirectory.path}'; + final Directory buildDirectory = dir(path.join( + cwd, + 'build', + )); + final String? appPath = + _findDarwinAppInBuildDirectory(buildDirectory.path); + if (appPath == null) { + throw 'Failed to find app bundle in ${buildDirectory.path}'; } - final String appPath = appBundle.path; - // IPAs are created manually, https://flutter.dev/ios-release/ - await exec('tar', ['-zcf', 'build/app.ipa', appPath]); - releaseSizeInBytes = await file('$cwd/build/app.ipa').length(); + // Validate changes in Dart snapshot format and data layout do not + // change compression size. This also simulates the size of an IPA on iOS. + await exec('tar', ['-zcf', 'build/app.tar.gz', appPath]); + releaseSizeInBytes = await file('$cwd/build/app.tar.gz').length(); if (reportPackageContentSizes) { - metrics.addAll(await getSizesFromIosApp(appPath)); + final Map sizeMetrics = await getSizesFromDarwinApp( + appPath: appPath, + operatingSystem: deviceOperatingSystem, + ); + metrics.addAll(sizeMetrics); } break; case DeviceOperatingSystem.android: @@ -1459,8 +1477,6 @@ class CompileTest { throw Exception('Unsupported option for fake devices'); case DeviceOperatingSystem.fuchsia: throw Exception('Unsupported option for Fuchsia devices'); - case DeviceOperatingSystem.macos: - throw Exception('Unsupported option for macOS devices'); case DeviceOperatingSystem.windows: unawaited(stderr.flush()); options.insert(0, 'windows'); @@ -1520,7 +1536,9 @@ class CompileTest { case DeviceOperatingSystem.fuchsia: throw Exception('Unsupported option for Fuchsia devices'); case DeviceOperatingSystem.macos: - throw Exception('Unsupported option for Fuchsia devices'); + unawaited(stderr.flush()); + options.insert(0, 'macos'); + break; case DeviceOperatingSystem.windows: unawaited(stderr.flush()); options.insert(0, 'windows'); @@ -1535,19 +1553,52 @@ class CompileTest { }; } - static Future> getSizesFromIosApp(String appPath) async { - // Thin the binary to only contain one architecture. - final String xcodeBackend = path.join(flutterDirectory.path, 'packages', 'flutter_tools', 'bin', 'xcode_backend.sh'); - await exec(xcodeBackend, ['thin'], environment: { - 'ARCHS': 'arm64', - 'WRAPPER_NAME': path.basename(appPath), - 'TARGET_BUILD_DIR': path.dirname(appPath), - }); + static Future> getSizesFromDarwinApp({ + required String appPath, + required DeviceOperatingSystem operatingSystem, + }) async { + late final File flutterFramework; + late final String frameworkDirectory; + switch (deviceOperatingSystem) { + case DeviceOperatingSystem.ios: + frameworkDirectory = path.join( + appPath, + 'Frameworks', + ); + flutterFramework = File(path.join( + frameworkDirectory, + 'Flutter.framework', + 'Flutter', + )); + break; + case DeviceOperatingSystem.macos: + frameworkDirectory = path.join( + appPath, + 'Contents', + 'Frameworks', + ); + flutterFramework = File(path.join( + frameworkDirectory, + 'FlutterMacOS.framework', + 'FlutterMacOS', + )); // https://github.com/flutter/flutter/issues/70413 + break; + case DeviceOperatingSystem.android: + case DeviceOperatingSystem.androidArm: + case DeviceOperatingSystem.androidArm64: + case DeviceOperatingSystem.fake: + case DeviceOperatingSystem.fuchsia: + case DeviceOperatingSystem.windows: + throw Exception('Called ${CompileTest.getSizesFromDarwinApp} with $operatingSystem.'); + } - final File appFramework = File(path.join(appPath, 'Frameworks', 'App.framework', 'App')); - final File flutterFramework = File(path.join(appPath, 'Frameworks', 'Flutter.framework', 'Flutter')); + final File appFramework = File(path.join( + frameworkDirectory, + 'App.framework', + 'App', + )); - return { + return { 'app_framework_uncompressed_bytes': await appFramework.length(), 'flutter_framework_uncompressed_bytes': await flutterFramework.length(), }; @@ -1908,8 +1959,9 @@ Future waitForFile(String path) async { throw StateError('Did not find vmservice out file after 1 hour'); } -String? _findIosAppInBuildDirectory(String searchDirectory) { - for (final FileSystemEntity entity in Directory(searchDirectory).listSync()) { +String? _findDarwinAppInBuildDirectory(String searchDirectory) { + for (final FileSystemEntity entity in Directory(searchDirectory) + .listSync(recursive: true)) { if (entity.path.endsWith('.app')) { return entity.path; } diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index db38cf2c0b8dd..a698357335678 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -8,20 +8,20 @@ environment: dependencies: archive: 3.3.1 args: 2.3.1 - file: 6.1.3 + file: 6.1.4 http: 0.13.5 logging: 1.0.2 meta: 1.8.0 - metrics_center: 1.0.5 + metrics_center: 1.0.6 path: 1.8.2 platform: 3.1.0 process: 4.2.4 - pubspec_parse: 1.2.0 + pubspec_parse: 1.2.1 shelf: 1.3.2 shelf_static: 1.1.1 stack_trace: 1.10.0 vm_service: 9.3.0 - webkit_inspection_protocol: 1.1.0 + webkit_inspection_protocol: 1.2.0 _discoveryapis_commons: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,8 +29,8 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - equatable: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + equatable: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,13 +45,13 @@ dependencies: yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,9 +64,9 @@ dev_dependencies: shelf_web_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ecac +# PUBSPEC CHECKSUM: 0ab5 diff --git a/dev/devicelab/test/runner_test.dart b/dev/devicelab/test/runner_test.dart index baee698e06327..e86843214895e 100644 --- a/dev/devicelab/test/runner_test.dart +++ b/dev/devicelab/test/runner_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_devicelab/framework/runner.dart'; import 'common.dart'; @@ -13,7 +11,7 @@ void main() { 'runFlutterConfig': 'false', 'timeoutInMinutes': '1', }; - List printLog; + late List printLog; void print(String s) => printLog.add(s); group('run.dart script', () { diff --git a/dev/devicelab/test/tasks/build_test_task_test.dart b/dev/devicelab/test/tasks/build_test_task_test.dart index 70bb86b5b647c..251fc7007378b 100644 --- a/dev/devicelab/test/tasks/build_test_task_test.dart +++ b/dev/devicelab/test/tasks/build_test_task_test.dart @@ -78,13 +78,13 @@ void main() { expect(result.message, 'Task failed: Exception: Both build and test should not be passed. Pass only one.'); }); - test('throws exception when build and application binary arg are given', () async { + test('copies artifacts when build and application binary arg are given', () async { final TaskResult result = await runTask( 'smoke_test_build_test', - taskArgs: ['--build', '--application-binary-path=test.apk'], + taskArgs: ['--build', '--application-binary-path=test'], deviceId: 'FAKE_SUCCESS', isolateParams: isolateParams, ); - expect(result.message, 'Task failed: Exception: Application binary path is only used for tests'); + expect(result.message, 'No tests run'); }); } diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index 555d7467302a8..ef074d963d6be 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: args: 2.3.1 - file: 6.1.3 + file: 6.1.4 package_config: 2.1.0 path: 1.8.2 process: 4.2.4 @@ -16,4 +16,4 @@ dependencies: meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 145e +# PUBSPEC CHECKSUM: db5f diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index c569d5150b4c8..a31d1d24b7bf9 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -14,9 +14,9 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dc60 +# PUBSPEC CHECKSUM: dd61 diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index a13bda933ccc8..3189c755eeacc 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -55,7 +55,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -95,4 +95,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 1e8a +# PUBSPEC CHECKSUM: 448c diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index f5c99c1c7fd66..9f9b2360cf4f4 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: flutter_test: sdk: flutter pub_semver: 2.1.1 - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,8 +26,8 @@ dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,18 +54,18 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index f8d79732330a3..7fe09cfde25d1 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -23,12 +23,12 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" ffi: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.0.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.0.20 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_ios: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_macos: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,19 +40,19 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 0.2.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 0.2.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,14 +82,14 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7778 +# PUBSPEC CHECKSUM: 5c78 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index cd39248c8d2f2..060a6d275337d 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -22,8 +22,8 @@ dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,18 +51,18 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fb32 +# PUBSPEC CHECKSUM: 2537 diff --git a/dev/integration_tests/channels/test_driver/main_test.dart b/dev/integration_tests/channels/test_driver/main_test.dart index 7f9f17175ff0e..17cee4a44fd53 100644 --- a/dev/integration_tests/channels/test_driver/main_test.dart +++ b/dev/integration_tests/channels/test_driver/main_test.dart @@ -18,6 +18,7 @@ void main() { final SerializableFinder statusField = find.byValueKey('status'); int step = 0; while (await driver.getText(statusField) == 'ok') { + print('Tapping for step $step...'); await driver.tap(stepButton); step++; } diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 64ad9cea24a0f..5422e52bc7935 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,17 +23,17 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,7 +41,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,11 +63,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index d87598f1421aa..6695dce6d8821 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -22,8 +22,8 @@ dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,18 +51,18 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fb32 +# PUBSPEC CHECKSUM: 2537 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 0ab32018aed25..b080f01361f40 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,8 +24,8 @@ dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,15 +53,15 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/dev/integration_tests/flutter_gallery/lib/demo/calculator/home.dart b/dev/integration_tests/flutter_gallery/lib/demo/calculator/home.dart index ea5eb8c56b49f..239526c1c667b 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/calculator/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/calculator/home.dart @@ -202,7 +202,7 @@ class KeyPad extends StatelessWidget { ), Expanded( child: Material( - color: themeData.backgroundColor, + color: themeData.colorScheme.background, child: Column( children: [ CalcKey('\u232B', calcState!.handleDelTap), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/colors_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/colors_demo.dart index 9c19a1750ff53..65bc6901e7126 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/colors_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/colors_demo.dart @@ -92,8 +92,8 @@ class PaletteTabView extends StatelessWidget { @override Widget build(BuildContext context) { final TextTheme textTheme = Theme.of(context).textTheme; - final TextStyle whiteTextStyle = textTheme.bodyText2!.copyWith(color: Colors.white); - final TextStyle blackTextStyle = textTheme.bodyText2!.copyWith(color: Colors.black); + final TextStyle whiteTextStyle = textTheme.bodyMedium!.copyWith(color: Colors.white); + final TextStyle blackTextStyle = textTheme.bodyMedium!.copyWith(color: Colors.black); return Scrollbar( child: ListView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/contacts_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/contacts_demo.dart index c9307a78c31d1..589067655526d 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/contacts_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/contacts_demo.dart @@ -20,7 +20,7 @@ class _ContactCategory extends StatelessWidget { border: Border(bottom: BorderSide(color: themeData.dividerColor)) ), child: DefaultTextStyle( - style: Theme.of(context).textTheme.subtitle1!, + style: Theme.of(context).textTheme.titleMedium!, child: SafeArea( top: false, bottom: false, @@ -64,7 +64,7 @@ class _ContactItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ ...lines.sublist(0, lines.length - 1).map((String line) => Text(line)), - Text(lines.last, style: themeData.textTheme.caption), + Text(lines.last, style: themeData.textTheme.bodySmall), ], ), ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/fortnightly/fortnightly.dart b/dev/integration_tests/flutter_gallery/lib/demo/fortnightly/fortnightly.dart index 7892bfa9b1ae2..789b6f655666f 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/fortnightly/fortnightly.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/fortnightly/fortnightly.dart @@ -117,29 +117,29 @@ over water meant for the whole central valley of California? The story will shoc children: [ Text( 'US', - style: textTheme.overline, + style: textTheme.labelSmall, ), Text( ' ¬ ', // TODO(larche): Replace textTheme.headline2.color with a ColorScheme value when known. - style: textTheme.overline!.apply(color: textTheme.headline2!.color), + style: textTheme.labelSmall!.apply(color: textTheme.displayMedium!.color), ), Text( 'CULTURE', - style: textTheme.overline, + style: textTheme.labelSmall, ), ], ), const SizedBox(height: 10), Text( 'Quince for Wisdom, Persimmon for Luck, Pomegranate for Love', - style: textTheme.headline4, + style: textTheme.headlineMedium, ), const SizedBox(height: 10), Text( 'How these crazy fruits sweetened our hearts, relationships, ' 'and puffed pastries', - style: textTheme.bodyText2, + style: textTheme.bodyMedium, ), Padding( padding: const EdgeInsets.symmetric(vertical: 16), @@ -155,7 +155,7 @@ over water meant for the whole central valley of California? The story will shoc const SizedBox(width: 12), Text( 'by', - style: textTheme.headline2, + style: textTheme.displayMedium, ), const SizedBox(width: 4), const Text( @@ -172,7 +172,7 @@ over water meant for the whole central valley of California? The story will shoc ), Text( '$paragraph1\n\n$paragraph2', - style: textTheme.bodyText1, + style: textTheme.bodyLarge, ), ], ), @@ -200,7 +200,7 @@ TextTheme _buildTextTheme(TextTheme base) { theme = theme.apply(displayColor: Colors.black); theme = theme.copyWith( - headline4: base.headline4!.copyWith( + headlineMedium: base.headlineMedium!.copyWith( fontFamily: 'Merriweather', fontStyle: FontStyle.italic, fontSize: 28, @@ -208,21 +208,21 @@ TextTheme _buildTextTheme(TextTheme base) { color: Colors.black, height: .88, ), - headline2: base.headline2!.copyWith( + displayMedium: base.displayMedium!.copyWith( fontFamily: 'LibreFranklin', fontSize: 18, fontWeight: FontWeight.w500, color: Colors.black.withAlpha(153), ), - headline5: base.headline5!.copyWith(fontWeight: FontWeight.w500), - bodyText2: base.bodyText2!.copyWith( + headlineSmall: base.headlineSmall!.copyWith(fontWeight: FontWeight.w500), + bodyMedium: base.bodyMedium!.copyWith( fontFamily: 'Merriweather', fontSize: 14, fontWeight: FontWeight.w300, color: const Color(0xFF666666), height: 1.11, ), - bodyText1: base.bodyText1!.copyWith( + bodyLarge: base.bodyLarge!.copyWith( fontFamily: 'Merriweather', fontSize: 16, fontWeight: FontWeight.w300, @@ -230,7 +230,7 @@ TextTheme _buildTextTheme(TextTheme base) { height: 1.4, letterSpacing: .25, ), - overline: const TextStyle( + labelSmall: const TextStyle( fontFamily: 'LibreFranklin', fontSize: 10, fontWeight: FontWeight.w700, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/backdrop_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/backdrop_demo.dart index 060d21c01323a..5623ab17290c1 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/backdrop_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/backdrop_demo.dart @@ -130,7 +130,7 @@ class CategoryView extends StatelessWidget { alignment: AlignmentDirectional.center, child: Text( asset, - style: theme.textTheme.caption, + style: theme.textTheme.bodySmall, ), ), ], @@ -186,7 +186,7 @@ class BackdropPanel extends StatelessWidget { padding: const EdgeInsetsDirectional.only(start: 16.0), alignment: AlignmentDirectional.centerStart, child: DefaultTextStyle( - style: theme.textTheme.subtitle1!, + style: theme.textTheme.titleMedium!, child: Tooltip( message: 'Tap to dismiss', child: title, @@ -213,7 +213,7 @@ class BackdropTitle extends AnimatedWidget { Widget build(BuildContext context) { final Animation animation = listenable as Animation; return DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.headline6!, + style: Theme.of(context).primaryTextTheme.titleLarge!, softWrap: false, overflow: TextOverflow.ellipsis, child: Stack( @@ -365,8 +365,8 @@ class _BackdropDemoState extends State with SingleTickerProviderSt children: [ ListTileTheme( iconColor: theme.primaryIconTheme.color, - textColor: theme.primaryTextTheme.headline6!.color!.withOpacity(0.6), - selectedColor: theme.primaryTextTheme.headline6!.color, + textColor: theme.primaryTextTheme.titleLarge!.color!.withOpacity(0.6), + selectedColor: theme.primaryTextTheme.titleLarge!.color, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/bottom_app_bar_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/bottom_app_bar_demo.dart index 81ec130797f78..bc36265adaa3c 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/bottom_app_bar_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/bottom_app_bar_demo.dart @@ -262,7 +262,7 @@ class _RadioItem extends StatelessWidget { }, child: Text( value.title!, - style: theme.textTheme.subtitle1, + style: theme.textTheme.titleMedium, ), ), ), @@ -332,7 +332,7 @@ class _Heading extends StatelessWidget { alignment: AlignmentDirectional.centerStart, child: Text( text, - style: theme.textTheme.bodyText1, + style: theme.textTheme.bodyLarge, ), ); } diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/cards_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/cards_demo.dart index 8746949cf9ecf..105c385af4a73 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/cards_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/cards_demo.dart @@ -231,7 +231,7 @@ class SectionTitle extends StatelessWidget { padding: const EdgeInsets.fromLTRB(4.0, 4.0, 4.0, 12.0), child: Align( alignment: Alignment.centerLeft, - child: Text(title!, style: Theme.of(context).textTheme.subtitle1), + child: Text(title!, style: Theme.of(context).textTheme.titleMedium), ), ); } @@ -245,8 +245,8 @@ class TravelDestinationContent extends StatelessWidget { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextStyle titleStyle = theme.textTheme.headline5!.copyWith(color: Colors.white); - final TextStyle descriptionStyle = theme.textTheme.subtitle1!; + final TextStyle titleStyle = theme.textTheme.headlineSmall!.copyWith(color: Colors.white); + final TextStyle descriptionStyle = theme.textTheme.titleMedium!; final ButtonStyle textButtonStyle = TextButton.styleFrom(foregroundColor: Colors.amber.shade500); return Column( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/chip_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/chip_demo.dart index 1c522837d6abb..19188dc24444a 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/chip_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/chip_demo.dart @@ -124,7 +124,7 @@ class _ChipsTile extends StatelessWidget { alignment: Alignment.center, constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0), padding: const EdgeInsets.all(8.0), - child: Text('None', style: Theme.of(context).textTheme.caption!.copyWith(fontStyle: FontStyle.italic)), + child: Text('None', style: Theme.of(context).textTheme.bodySmall!.copyWith(fontStyle: FontStyle.italic)), ), ), ], @@ -194,16 +194,16 @@ class _ChipDemoState extends State { } // This converts a String to a unique color, based on the hash value of the - // String object. It takes the bottom 16 bits of the hash, and uses that to + // String object. It takes the bottom 16 bits of the hash, and uses that to // pick a hue for an HSV color, and then creates the color (with a preset - // saturation and value). This means that any unique strings will also have + // saturation and value). This means that any unique strings will also have // unique colors, but they'll all be readable, since they have the same // saturation and value. Color _nameToColor(String name, ThemeData theme) { assert(name.length > 1); final int hash = name.hashCode & 0xffff; final double hue = (360.0 * hash / (1 << 15)) % 360.0; - final double themeValue = HSVColor.fromColor(theme.backgroundColor).value; + final double themeValue = HSVColor.fromColor(theme.colorScheme.background).value; return HSVColor.fromAHSV(1.0, hue, 0.4, themeValue).toColor(); } @@ -318,7 +318,7 @@ class _ChipDemoState extends State { child: Center( child: Text( _createResult(), - style: theme.textTheme.headline6, + style: theme.textTheme.titleLarge, ), ), ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart index 6349bdf160f4e..fa7554e27a833 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart @@ -83,7 +83,7 @@ class _DateTimePicker extends StatelessWidget { @override Widget build(BuildContext context) { - final TextStyle? valueStyle = Theme.of(context).textTheme.headline6; + final TextStyle? valueStyle = Theme.of(context).textTheme.titleLarge; return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -147,13 +147,13 @@ class _DateAndTimePickerDemoState extends State { labelText: 'Event name', border: OutlineInputBorder(), ), - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), TextField( decoration: const InputDecoration( labelText: 'Location', ), - style: Theme.of(context).textTheme.headline4!.copyWith(fontSize: 20.0), + style: Theme.of(context).textTheme.headlineMedium!.copyWith(fontSize: 20.0), ), _DateTimePicker( labelText: 'From', diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/dialog_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/dialog_demo.dart index e5fb743bfddce..04a2c13b5fd8a 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/dialog_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/dialog_demo.dart @@ -82,7 +82,7 @@ class DialogDemoState extends State { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + final TextStyle dialogTextStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); return Scaffold( appBar: AppBar( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/drawer_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/drawer_demo.dart index 695d164da798e..bf1291f9b8d92 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/drawer_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/drawer_demo.dart @@ -237,7 +237,7 @@ class _DrawerDemoState extends State with TickerProviderStateMixin { Padding( padding: const EdgeInsets.only(top: 8.0), child: Text('Tap here to open the drawer', - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, ), ), ], diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/expansion_panels_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/expansion_panels_demo.dart index cad7f3b6e9643..1fbe805ea019b 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/expansion_panels_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/expansion_panels_demo.dart @@ -58,7 +58,7 @@ class DualHeaderWithHint extends StatelessWidget { alignment: Alignment.centerLeft, child: Text( name!, - style: textTheme.bodyText2!.copyWith(fontSize: 15.0), + style: textTheme.bodyMedium!.copyWith(fontSize: 15.0), ), ), ), @@ -68,8 +68,8 @@ class DualHeaderWithHint extends StatelessWidget { child: Container( margin: const EdgeInsets.only(left: 24.0), child: _crossFade( - Text(value!, style: textTheme.caption!.copyWith(fontSize: 15.0)), - Text(hint!, style: textTheme.caption!.copyWith(fontSize: 15.0)), + Text(value!, style: textTheme.bodySmall!.copyWith(fontSize: 15.0)), + Text(hint!, style: textTheme.bodySmall!.copyWith(fontSize: 15.0)), showHint!, ), ), @@ -108,7 +108,7 @@ class CollapsibleBody extends StatelessWidget { ) - margin, child: Center( child: DefaultTextStyle( - style: textTheme.caption!.copyWith(fontSize: 15.0), + style: textTheme.bodySmall!.copyWith(fontSize: 15.0), child: child!, ), ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart index 8918dfb668ab6..b6f7bbe6b6afb 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart @@ -28,7 +28,7 @@ class DateTimeItem extends StatelessWidget { final ThemeData theme = Theme.of(context); return DefaultTextStyle( - style: theme.textTheme.subtitle1!, + style: theme.textTheme.titleMedium!, child: Row( children: [ Expanded( @@ -116,7 +116,7 @@ class FullScreenDialogDemoState extends State { } final ThemeData theme = Theme.of(context); - final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + final TextStyle dialogTextStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); return showDialog( context: context, @@ -154,7 +154,7 @@ class FullScreenDialogDemoState extends State { title: Text(_hasName ? _eventName : 'Event Name TBD'), actions: [ TextButton( - child: Text('SAVE', style: theme.textTheme.bodyText2!.copyWith(color: Colors.white)), + child: Text('SAVE', style: theme.textTheme.bodyMedium!.copyWith(color: Colors.white)), onPressed: () { Navigator.pop(context, DismissDialogAction.save); }, @@ -176,7 +176,7 @@ class FullScreenDialogDemoState extends State { labelText: 'Event name', filled: true, ), - style: theme.textTheme.headline5, + style: theme.textTheme.headlineSmall, onChanged: (String value) { setState(() { _hasName = value.isNotEmpty; @@ -206,7 +206,7 @@ class FullScreenDialogDemoState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('From', style: theme.textTheme.caption), + Text('From', style: theme.textTheme.bodySmall), DateTimeItem( dateTime: _fromDateTime, onChanged: (DateTime value) { @@ -221,7 +221,7 @@ class FullScreenDialogDemoState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('To', style: theme.textTheme.caption), + Text('To', style: theme.textTheme.bodySmall), DateTimeItem( dateTime: _toDateTime, onChanged: (DateTime value) { diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/icons_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/icons_demo.dart index 9ce90a4518831..ec81fd7fff462 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/icons_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/icons_demo.dart @@ -112,7 +112,7 @@ class _IconsDemoCard extends StatelessWidget { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextStyle textStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + final TextStyle textStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); return Card( child: DefaultTextStyle( style: textStyle, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/progress_indicator_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/progress_indicator_demo.dart index c4788786c9359..37cd0062cb5ac 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/progress_indicator_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/progress_indicator_demo.dart @@ -115,7 +115,7 @@ class _ProgressIndicatorDemoState extends State with Sing body: Center( child: SingleChildScrollView( child: DefaultTextStyle( - style: Theme.of(context).textTheme.headline6!, + style: Theme.of(context).textTheme.titleLarge!, child: GestureDetector( onTap: _handleTap, behavior: HitTestBehavior.opaque, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/reorderable_list_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/reorderable_list_demo.dart index ee74a5bcc8841..460d376e266e3 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/reorderable_list_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/reorderable_list_demo.dart @@ -212,7 +212,7 @@ class _ListDemoState extends State { header: _itemType != _ReorderableListType.threeLine ? Padding( padding: const EdgeInsets.all(8.0), - child: Text('Header of the list', style: Theme.of(context).textTheme.headline5)) + child: Text('Header of the list', style: Theme.of(context).textTheme.headlineSmall)) : null, onReorder: _onReorder, reverse: _reverse!, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/search_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/search_demo.dart index 8b3c09f6f0770..bb50d425ab6bd 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/search_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/search_demo.dart @@ -255,7 +255,7 @@ class _ResultCard extends StatelessWidget { Text(title!), Text( '$integer', - style: theme.textTheme.headline5!.copyWith(fontSize: 72.0), + style: theme.textTheme.headlineSmall!.copyWith(fontSize: 72.0), ), ], ), @@ -284,11 +284,11 @@ class _SuggestionList extends StatelessWidget { title: RichText( text: TextSpan( text: suggestion.substring(0, query!.length), - style: theme.textTheme.subtitle1!.copyWith(fontWeight: FontWeight.bold), + style: theme.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold), children: [ TextSpan( text: suggestion.substring(query!.length), - style: theme.textTheme.subtitle1, + style: theme.textTheme.titleMedium, ), ], ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart index 5494761668b59..03215720f71f7 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/slider_demo.dart @@ -334,7 +334,7 @@ class _SlidersState extends State<_Sliders> { valueIndicatorColor: Colors.deepPurpleAccent, thumbShape: _CustomThumbShape(), valueIndicatorShape: _CustomValueIndicatorShape(), - valueIndicatorTextStyle: theme.textTheme.bodyText1!.copyWith(color: theme.colorScheme.onSurface), + valueIndicatorTextStyle: theme.textTheme.bodyLarge!.copyWith(color: theme.colorScheme.onSurface), ), child: Slider( value: _discreteCustomValue, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_demo.dart index e461e37a98ccc..428ce27208078 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_demo.dart @@ -126,7 +126,7 @@ class _CardDataItem extends StatelessWidget { Center( child: Text( data!.title!, - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.titleLarge, ), ), ], diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_fab_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_fab_demo.dart index 582651d81ca6e..a9887ece893fd 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_fab_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/tabs_fab_demo.dart @@ -78,7 +78,7 @@ class _TabsFabDemoState extends State with SingleTickerProviderStat ), child: Padding( padding: const EdgeInsets.all(32.0), - child: Text(_explanatoryText, style: Theme.of(context).textTheme.subtitle1), + child: Text(_explanatoryText, style: Theme.of(context).textTheme.titleMedium), ), ); }); diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart index bcf5288a4a2a8..5d3fee8d60f0c 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart @@ -293,7 +293,7 @@ class TextFormFieldDemoState extends State { const SizedBox(height: 24.0), Text( '* indicates required field', - style: Theme.of(context).textTheme.caption, + style: Theme.of(context).textTheme.bodySmall, ), const SizedBox(height: 24.0), ], diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/tooltip_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/tooltip_demo.dart index af66b74de79ea..69fa9629b5685 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/tooltip_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/tooltip_demo.dart @@ -31,10 +31,10 @@ class TooltipDemo extends StatelessWidget { bottom: false, child: ListView( children: [ - Text(_introText, style: theme.textTheme.subtitle1), + Text(_introText, style: theme.textTheme.titleMedium), Row( children: [ - Text('Long press the ', style: theme.textTheme.subtitle1), + Text('Long press the ', style: theme.textTheme.titleMedium), Tooltip( message: 'call icon', child: Icon( @@ -43,7 +43,7 @@ class TooltipDemo extends StatelessWidget { color: theme.iconTheme.color, ), ), - Text(' icon.', style: theme.textTheme.subtitle1), + Text(' icon.', style: theme.textTheme.titleMedium), ], ), Center( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart index cf62ff50a854b..dd9db3b926ecd 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart @@ -87,7 +87,6 @@ ThemeData _buildShrineTheme() { primaryColor: kShrinePink100, scaffoldBackgroundColor: kShrineBackgroundWhite, cardColor: kShrineBackgroundWhite, - errorColor: kShrineErrorRed, primaryIconTheme: _customIconTheme(base.iconTheme), inputDecorationTheme: const InputDecorationTheme(border: CutCornersBorder()), textTheme: _buildShrineTextTheme(base.textTheme), @@ -98,11 +97,11 @@ ThemeData _buildShrineTheme() { TextTheme _buildShrineTextTheme(TextTheme base) { return base.copyWith( - headline5: base.headline5!.copyWith(fontWeight: FontWeight.w500), - headline6: base.headline6!.copyWith(fontSize: 18.0), - caption: base.caption!.copyWith(fontWeight: FontWeight.w400, fontSize: 14.0), - bodyText1: base.bodyText1!.copyWith(fontWeight: FontWeight.w500, fontSize: 16.0), - button: base.button!.copyWith(fontWeight: FontWeight.w500, fontSize: 14.0), + headlineSmall: base.headlineSmall!.copyWith(fontWeight: FontWeight.w500), + titleLarge: base.titleLarge!.copyWith(fontSize: 18.0), + bodySmall: base.bodySmall!.copyWith(fontWeight: FontWeight.w400, fontSize: 14.0), + bodyLarge: base.bodyLarge!.copyWith(fontWeight: FontWeight.w500, fontSize: 16.0), + labelLarge: base.labelLarge!.copyWith(fontWeight: FontWeight.w500, fontSize: 14.0), ).apply( fontFamily: 'Raleway', displayColor: kShrineBrown900, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/backdrop.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/backdrop.dart index c4d77ba62ff8c..94f57663898a5 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/backdrop.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/backdrop.dart @@ -125,7 +125,7 @@ class _BackdropTitle extends AnimatedWidget { ); return DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.headline6!, + style: Theme.of(context).primaryTextTheme.titleLarge!, softWrap: false, overflow: TextOverflow.ellipsis, child: Row(children: [ diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/category_menu_page.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/category_menu_page.dart index 7d31212dd78d8..b822b054da9a1 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/category_menu_page.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/category_menu_page.dart @@ -33,7 +33,7 @@ class CategoryMenuPage extends StatelessWidget { const SizedBox(height: 16.0), Text( categoryString, - style: theme.textTheme.bodyText1, + style: theme.textTheme.bodyLarge, textAlign: TextAlign.center, ), const SizedBox(height: 14.0), @@ -48,7 +48,7 @@ class CategoryMenuPage extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 16.0), child: Text( categoryString, - style: theme.textTheme.bodyText1!.copyWith( + style: theme.textTheme.bodyLarge!.copyWith( color: kShrineBrown900.withAlpha(153) ), textAlign: TextAlign.center, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart index 34eede5e5c101..0391ef95bee47 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart @@ -542,7 +542,7 @@ class ExtraProductsNumber extends StatelessWidget { final int displayedOverflowProducts = numOverflowProducts <= 99 ? numOverflowProducts : 99; return Text( '+$displayedOverflowProducts', - style: Theme.of(context).primaryTextTheme.button, + style: Theme.of(context).primaryTextTheme.labelLarge, ); } diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart index e098319ae273b..ba11ceaa0bc65 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart @@ -51,7 +51,7 @@ class _LoginPageState extends State { const SizedBox(height: 16.0), Text( 'SHRINE', - style: Theme.of(context).textTheme.headline5, + style: Theme.of(context).textTheme.headlineSmall, ), ], ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/shopping_cart.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/shopping_cart.dart index 56aeb0a109376..8d2ec6f46dd12 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/shopping_cart.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/shopping_cart.dart @@ -58,7 +58,7 @@ class _ShoppingCartPageState extends State { ), Text( 'CART', - style: localTheme.textTheme.subtitle1!.copyWith(fontWeight: FontWeight.w600), + style: localTheme.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600), ), const SizedBox(width: 16.0), Text('${model.totalCartQuantity} ITEMS'), @@ -109,8 +109,8 @@ class ShoppingCartSummary extends StatelessWidget { @override Widget build(BuildContext context) { - final TextStyle smallAmountStyle = Theme.of(context).textTheme.bodyText2!.copyWith(color: kShrineBrown600); - final TextStyle? largeAmountStyle = Theme.of(context).textTheme.headline4; + final TextStyle smallAmountStyle = Theme.of(context).textTheme.bodyMedium!.copyWith(color: kShrineBrown600); + final TextStyle? largeAmountStyle = Theme.of(context).textTheme.headlineMedium; final NumberFormat formatter = NumberFormat.simpleCurrency( decimalDigits: 2, locale: Localizations.localeOf(context).toString(), @@ -243,7 +243,7 @@ class ShoppingCartRow extends StatelessWidget { ), Text( product.name, - style: localTheme.textTheme.subtitle1!.copyWith(fontWeight: FontWeight.w600), + style: localTheme.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600), ), ], ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart index 17ff0fe0f74e9..b5d4083d9cbda 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart @@ -59,7 +59,7 @@ class ProductCard extends StatelessWidget { children: [ Text( product == null ? '' : product!.name, - style: theme.textTheme.button, + style: theme.textTheme.labelLarge, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 1, @@ -67,7 +67,7 @@ class ProductCard extends StatelessWidget { const SizedBox(height: 4.0), Text( product == null ? '' : formatter.format(product!.price), - style: theme.textTheme.caption, + style: theme.textTheme.bodySmall, ), ], ), diff --git a/dev/integration_tests/flutter_gallery/lib/demo/typography_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/typography_demo.dart index 1ff1c460e4d0e..4047e4ecc602d 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/typography_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/typography_demo.dart @@ -19,7 +19,7 @@ class TextStyleItem extends StatelessWidget { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextStyle nameStyle = theme.textTheme.caption!.copyWith(color: theme.textTheme.caption!.color); + final TextStyle nameStyle = theme.textTheme.bodySmall!.copyWith(color: theme.textTheme.bodySmall!.color); return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0), child: Row( @@ -47,18 +47,21 @@ class TypographyDemo extends StatelessWidget { Widget build(BuildContext context) { final TextTheme textTheme = Theme.of(context).textTheme; final List styleItems = [ - if (MediaQuery.of(context).size.width > 500.0) - TextStyleItem(name: 'Headline 1', style: textTheme.headline1!, text: 'Light 112sp'), - TextStyleItem(name: 'Headline 2', style: textTheme.headline2!, text: 'Regular 56sp'), - TextStyleItem(name: 'Headline 3', style: textTheme.headline3!, text: 'Regular 45sp'), - TextStyleItem(name: 'Headline 4', style: textTheme.headline4!, text: 'Regular 34sp'), - TextStyleItem(name: 'Headline 5', style: textTheme.headline5!, text: 'Regular 24sp'), - TextStyleItem(name: 'Headline 6', style: textTheme.headline6!, text: 'Medium 20sp'), - TextStyleItem(name: 'Subtitle 1', style: textTheme.subtitle1!, text: 'Regular 16sp'), - TextStyleItem(name: 'Body 1', style: textTheme.bodyText1!, text: 'Medium 14sp'), - TextStyleItem(name: 'Body 2', style: textTheme.bodyText2!, text: 'Regular 14sp'), - TextStyleItem(name: 'Caption', style: textTheme.caption!, text: 'Regular 12sp'), - TextStyleItem(name: 'Button', style: textTheme.button!, text: 'MEDIUM (ALL CAPS) 14sp'), + TextStyleItem(name: 'Display Large', style: textTheme.displayLarge!, text: 'Regular 57/64 +0'), + TextStyleItem(name: 'Display Medium', style: textTheme.displayMedium!, text: 'Regular 45/52 +0'), + TextStyleItem(name: 'Display Small', style: textTheme.displaySmall!, text: 'Regular 36/44 +0'), + TextStyleItem(name: 'Headline Large', style: textTheme.headlineLarge!, text: 'Regular 32/40 +0'), + TextStyleItem(name: 'Headline Medium', style: textTheme.headlineMedium!, text: 'Regular 28/36 +0'), + TextStyleItem(name: 'Headline Small', style: textTheme.headlineSmall!, text: 'Regular 24/32 +0'), + TextStyleItem(name: 'Title Large', style: textTheme.titleLarge!, text: 'Medium 22/28 +0'), + TextStyleItem(name: 'Title Medium', style: textTheme.titleMedium!, text: 'Medium 16/24 +0.15'), + TextStyleItem(name: 'Title Small', style: textTheme.titleSmall!, text: 'Medium 14/20 +0.1'), + TextStyleItem(name: 'Body Large', style: textTheme.bodyLarge!, text: 'Regular 16/24 +0.5'), + TextStyleItem(name: 'Body Medium', style: textTheme.bodyMedium!, text: 'Regular 14/20 +0.25'), + TextStyleItem(name: 'Body Small', style: textTheme.bodySmall!, text: 'Regular 12/16 +0.4'), + TextStyleItem(name: 'Label Large', style: textTheme.labelLarge!, text: 'Medium 14/20 +0.1'), + TextStyleItem(name: 'Label Medium', style: textTheme.labelMedium!, text: 'Medium 12/16 +0.5'), + TextStyleItem(name: 'Label Small', style: textTheme.labelSmall!, text: 'Medium 11/16 +0.5'), ]; return Scaffold( diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/about.dart b/dev/integration_tests/flutter_gallery/lib/gallery/about.dart index 43ffd5c75449c..fb28d9b6655b0 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/about.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/about.dart @@ -32,8 +32,8 @@ class _LinkTextSpan extends TextSpan { void showGalleryAboutDialog(BuildContext context) { final ThemeData themeData = Theme.of(context); - final TextStyle? aboutTextStyle = themeData.textTheme.bodyText1; - final TextStyle linkStyle = themeData.textTheme.bodyText1!.copyWith(color: themeData.colorScheme.primary); + final TextStyle? aboutTextStyle = themeData.textTheme.bodyLarge; + final TextStyle linkStyle = themeData.textTheme.bodyLarge!.copyWith(color: themeData.colorScheme.primary); showAboutDialog( context: context, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/backdrop.dart b/dev/integration_tests/flutter_gallery/lib/gallery/backdrop.dart index 6c1e296155133..7f6a56303dc47 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/backdrop.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/backdrop.dart @@ -147,7 +147,7 @@ class _BackAppBar extends StatelessWidget { return IconTheme.merge( data: theme.primaryIconTheme, child: DefaultTextStyle( - style: theme.primaryTextTheme.headline6!, + style: theme.primaryTextTheme.titleLarge!, child: SizedBox( height: _kBackAppBarHeight, child: Row( diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/demo.dart b/dev/integration_tests/flutter_gallery/lib/gallery/demo.dart index 9c9d115238045..c01ac5d1574e3 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/demo.dart @@ -136,7 +136,7 @@ class TabbedComponentDemoScaffold extends StatelessWidget { Padding( padding: const EdgeInsets.all(16.0), child: Text(demo.description!, - style: Theme.of(context).textTheme.subtitle1, + style: Theme.of(context).textTheme.titleMedium, ), ), Expanded(child: demo.demoWidget!), diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart index 9b1208684f159..ebbce5404ecba 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart @@ -79,7 +79,7 @@ class _CategoryItem extends StatelessWidget { child: Text( category!.name, textAlign: TextAlign.center, - style: theme.textTheme.subtitle1!.copyWith( + style: theme.textTheme.titleMedium!.copyWith( fontFamily: 'GoogleSans', color: isDark ? Colors.white : _kFlutterBlue, ), @@ -206,14 +206,14 @@ class _DemoItem extends StatelessWidget { children: [ Text( demo!.title, - style: theme.textTheme.subtitle1!.copyWith( + style: theme.textTheme.titleMedium!.copyWith( color: isDark ? Colors.white : const Color(0xFF202124), ), ), if (demo!.subtitle != null) Text( demo!.subtitle!, - style: theme.textTheme.bodyText2!.copyWith( + style: theme.textTheme.bodyMedium!.copyWith( color: isDark ? Colors.white : const Color(0xFF60646B) ), ), diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/options.dart b/dev/integration_tests/flutter_gallery/lib/gallery/options.dart index 7c408f2199fba..c1c4b8314e5fe 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/options.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/options.dart @@ -179,7 +179,7 @@ class _TextButton extends StatelessWidget { return TextButton( style: TextButton.styleFrom( foregroundColor: theme.colorScheme.onPrimary, - textStyle: theme.textTheme.subtitle1, + textStyle: theme.textTheme.titleMedium, padding: EdgeInsets.zero, ), onPressed: onPressed, @@ -198,7 +198,7 @@ class _Heading extends StatelessWidget { final ThemeData theme = Theme.of(context); return _OptionsItem( child: DefaultTextStyle( - style: theme.textTheme.headline6!.copyWith( + style: theme.textTheme.titleLarge!.copyWith( fontFamily: 'GoogleSans', color: theme.colorScheme.onPrimary, fontWeight: FontWeight.w700, @@ -236,7 +236,7 @@ class _ThemeModeItem extends StatelessWidget { const Text('Theme'), Text( modeLabels[options!.themeMode!]!, - style: Theme.of(context).primaryTextTheme.bodyText2, + style: Theme.of(context).primaryTextTheme.bodyMedium, ), ], ), @@ -283,7 +283,7 @@ class _TextScaleFactorItem extends StatelessWidget { const Text('Text size'), Text( options!.textScaleFactor!.label, - style: Theme.of(context).primaryTextTheme.bodyText2, + style: Theme.of(context).primaryTextTheme.bodyMedium, ), ], ), @@ -329,7 +329,7 @@ class _VisualDensityItem extends StatelessWidget { const Text('Visual density'), Text( options!.visualDensity!.label, - style: Theme.of(context).primaryTextTheme.bodyText2, + style: Theme.of(context).primaryTextTheme.bodyMedium, ), ], ), @@ -438,7 +438,7 @@ class _PlatformItem extends StatelessWidget { const Text('Platform mechanics'), Text( _platformLabel(options!.platform!), - style: Theme.of(context).primaryTextTheme.bodyText2, + style: Theme.of(context).primaryTextTheme.bodyMedium, ), ], ), @@ -517,7 +517,7 @@ class GalleryOptionsPage extends StatelessWidget { final ThemeData theme = Theme.of(context); return DefaultTextStyle( - style: theme.primaryTextTheme.subtitle1!, + style: theme.primaryTextTheme.titleMedium!, child: ListView( padding: const EdgeInsets.only(bottom: 124.0), children: [ diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart b/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart index f12de0cce1b0a..66b7d7a762abf 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/themes.dart @@ -9,7 +9,7 @@ final ThemeData kDarkGalleryTheme = _buildDarkTheme(); TextTheme _buildTextTheme(TextTheme base) { return base.copyWith( - headline6: base.headline6!.copyWith( + titleLarge: base.titleLarge!.copyWith( fontFamily: 'GoogleSans', ), ); @@ -22,6 +22,8 @@ ThemeData _buildDarkTheme() { primary: primaryColor, secondary: secondaryColor, onPrimary: Colors.white, + error: const Color(0xFFB00020), + background: const Color(0xFF202124), ); final ThemeData base = ThemeData( brightness: Brightness.dark, @@ -32,8 +34,6 @@ ThemeData _buildDarkTheme() { indicatorColor: Colors.white, canvasColor: const Color(0xFF202124), scaffoldBackgroundColor: const Color(0xFF202124), - backgroundColor: const Color(0xFF202124), - errorColor: const Color(0xFFB00020), ); return base.copyWith( textTheme: _buildTextTheme(base.textTheme), @@ -47,6 +47,7 @@ ThemeData _buildLightTheme() { final ColorScheme colorScheme = const ColorScheme.light().copyWith( primary: primaryColor, secondary: secondaryColor, + error: const Color(0xFFB00020), ); final ThemeData base = ThemeData( brightness: Brightness.light, @@ -57,8 +58,6 @@ ThemeData _buildLightTheme() { splashFactory: InkRipple.splashFactory, canvasColor: Colors.white, scaffoldBackgroundColor: Colors.white, - backgroundColor: Colors.white, - errorColor: const Color(0xFFB00020), ); return base.copyWith( textTheme: _buildTextTheme(base.textTheme), diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/updater.dart b/dev/integration_tests/flutter_gallery/lib/gallery/updater.dart index befb271e733a7..b9cb37c3f75d0 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/updater.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/updater.dart @@ -44,7 +44,7 @@ class UpdaterState extends State { Widget _buildDialog(BuildContext context) { final ThemeData theme = Theme.of(context); final TextStyle dialogTextStyle = - theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color); + theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); return AlertDialog( title: const Text('Update Flutter Gallery?'), content: Text('A newer version is available.', style: dialogTextStyle), diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 3a2d9e813f07e..d0ff9728b7e28 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: url_launcher_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_web: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 5.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_web: 2.0.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,12 +57,12 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.21.4 + test: 1.21.5 integration_test: sdk: flutter - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,8 +71,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -95,14 +95,14 @@ dev_dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 06ef +# PUBSPEC CHECKSUM: 09f4 diff --git a/dev/integration_tests/flutter_gallery/windows/runner/flutter_window.cpp b/dev/integration_tests/flutter_gallery/windows/runner/flutter_window.cpp index 9cbd3109c3fee..f68aa9c26c0f5 100644 --- a/dev/integration_tests/flutter_gallery/windows/runner/flutter_window.cpp +++ b/dev/integration_tests/flutter_gallery/windows/runner/flutter_window.cpp @@ -30,6 +30,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/dev/integration_tests/flutter_gallery/windows/runner/main.cpp b/dev/integration_tests/flutter_gallery/windows/runner/main.cpp index 139eb1fa305f8..5afa6e1d166a3 100644 --- a/dev/integration_tests/flutter_gallery/windows/runner/main.cpp +++ b/dev/integration_tests/flutter_gallery/windows/runner/main.cpp @@ -31,7 +31,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"flutter_gallery", origin, size)) { + if (!window.Create(L"flutter_gallery", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/dev/integration_tests/flutter_gallery/windows/runner/win32_window.cpp b/dev/integration_tests/flutter_gallery/windows/runner/win32_window.cpp index 4021a2cfd40a1..635a5b29f532c 100644 --- a/dev/integration_tests/flutter_gallery/windows/runner/win32_window.cpp +++ b/dev/integration_tests/flutter_gallery/windows/runner/win32_window.cpp @@ -106,9 +106,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -121,7 +121,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -133,6 +133,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, diff --git a/dev/integration_tests/flutter_gallery/windows/runner/win32_window.h b/dev/integration_tests/flutter_gallery/windows/runner/win32_window.h index 1dab1777c4950..b161e9b84b8b3 100644 --- a/dev/integration_tests/flutter_gallery/windows/runner/win32_window.h +++ b/dev/integration_tests/flutter_gallery/windows/runner/win32_window.h @@ -32,15 +32,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 47471c9c8b43b..ea256a1c3e07b 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: camera: 0.10.0+1 camera_android: 0.10.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_avfoundation: 0.9.8+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_avfoundation: 0.9.8+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,9 +26,9 @@ dependencies: quiver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_transform: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: af98 +# PUBSPEC CHECKSUM: cb9b diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 07e22882d1a87..a39c97a6c7b20 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -23,12 +23,12 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" ffi: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.0.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.0.20 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_ios: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_macos: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,19 +40,19 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 0.2.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 0.2.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,14 +82,14 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7778 +# PUBSPEC CHECKSUM: 5c78 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index 90ba60681254b..905031e65c4db 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -48,7 +48,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: # The following line ensures that the Material Icons font is @@ -98,4 +98,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: 2662 +# PUBSPEC CHECKSUM: 4c64 diff --git a/dev/integration_tests/ios_app_with_extensions/lib/main.dart b/dev/integration_tests/ios_app_with_extensions/lib/main.dart index 0936e3b159d91..319889e207d1b 100644 --- a/dev/integration_tests/ios_app_with_extensions/lib/main.dart +++ b/dev/integration_tests/ios_app_with_extensions/lib/main.dart @@ -102,7 +102,7 @@ class _MyHomePageState extends State { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 751b83b7084be..f8842ab9d2037 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -50,7 +50,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -90,4 +90,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: f3e5 +# PUBSPEC CHECKSUM: 1ae7 diff --git a/dev/integration_tests/ios_platform_view_tests/ios/PlatformViewUITests/PlatformViewUITests.m b/dev/integration_tests/ios_platform_view_tests/ios/PlatformViewUITests/PlatformViewUITests.m index adcf947cb6c81..63ea56625cd25 100644 --- a/dev/integration_tests/ios_platform_view_tests/ios/PlatformViewUITests/PlatformViewUITests.m +++ b/dev/integration_tests/ios_platform_view_tests/ios/PlatformViewUITests/PlatformViewUITests.m @@ -23,19 +23,53 @@ @interface PlatformViewUITests : XCTestCase @implementation PlatformViewUITests - (void)setUp { - [super setup]; + [super setUp]; self.continueAfterFailure = NO; + // Delete the previously installed app if needed before running. + // This is to address "Failed to terminate" failure. + // The solution is based on https://stackoverflow.com/questions/50016018/uitest-failed-to-terminate-com-test-abc3708-after-60-0s-state-is-still-runnin + XCUIApplication *springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"]; + [springboard activate]; + XCUIElement *appIcon = springboard.icons[@"ios_platform_view_tests"]; + + if ([appIcon waitForExistenceWithTimeout:kStandardTimeOut]) { + NSLog(@"Deleting previously installed app."); + + // It's possible that app icon is not hittable yet. + NSPredicate *hittable = [NSPredicate predicateWithFormat:@"exists == YES AND hittable == YES"]; + [self expectationForPredicate:hittable evaluatedWithObject:appIcon handler:nil]; + [self waitForExpectationsWithTimeout:kStandardTimeOut handler:nil]; + + // Pressing for 2 seconds will bring up context menu. + // Pressing for 3 seconds will dismiss the context menu and make icons wiggle. + [appIcon pressForDuration:2]; + + // The "Remove App" button in context menu. + XCUIElement *contextMenuRemoveButton = springboard.buttons[@"Remove App"]; + XCTAssert([contextMenuRemoveButton waitForExistenceWithTimeout:kStandardTimeOut], @"The context menu remove app button must appear."); + [contextMenuRemoveButton tap]; + + // Tap the delete confirmation + XCUIElement *deleteConfirmationButton = springboard.alerts.buttons[@"Delete App"]; + XCTAssert([deleteConfirmationButton waitForExistenceWithTimeout:kStandardTimeOut], @"The first delete confirmation button must appear."); + [deleteConfirmationButton tap]; + + // Tap the second delete confirmation + XCUIElement *secondDeleteConfirmationButton = springboard.alerts.buttons[@"Delete"]; + XCTAssert([secondDeleteConfirmationButton waitForExistenceWithTimeout:kStandardTimeOut], @"The second delete confirmation button must appear."); + [secondDeleteConfirmationButton tap]; + + [NSThread sleepForTimeInterval:3]; + } else { + NSLog(@"No previously installed app found."); + } + self.app = [[XCUIApplication alloc] init]; [self.app launch]; } - (void)tearDown { - // This is trying to fix a "failed to terminate" failure, which is likely a bug in Xcode. - // In theory the terminate call is not necessary, but many has encountered this similar - // issue, and fixed it by terminating the app and relaunching it if needed for each test. - // Here we simply try terminating the app in tearDown, but if it does not work, - // then alternative solution is to terminate and relaunch the app. [self.app terminate]; [super tearDown]; } diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index d0e26fec78062..5f02b85b43126 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,17 +23,17 @@ dependencies: stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,7 +41,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,11 +63,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index 56aaf2a822d8b..9828529b0fb27 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -33,9 +33,9 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2662 +# PUBSPEC CHECKSUM: 4c64 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 206285994b964..134025921638e 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -22,8 +22,8 @@ dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,18 +51,18 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fb32 +# PUBSPEC CHECKSUM: 2537 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 4689746f26da0..beb7a318ded1b 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -30,7 +30,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3945 +# PUBSPEC CHECKSUM: a347 diff --git a/dev/integration_tests/spell_check/android/app/src/main/res/drawable/launch_background.xml b/dev/integration_tests/spell_check/android/app/src/main/res/drawable/launch_background.xml index 32d7798786856..3727f9e00a029 100644 --- a/dev/integration_tests/spell_check/android/app/src/main/res/drawable/launch_background.xml +++ b/dev/integration_tests/spell_check/android/app/src/main/res/drawable/launch_background.xml @@ -1,8 +1,8 @@ + - diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index e2640aadc93ac..9b430457bbb60 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -64,7 +64,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -105,4 +105,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 53ec +# PUBSPEC CHECKSUM: bdee diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 886e90f88f2d1..6a2cea442c1fd 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -15,10 +15,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,8 +28,8 @@ dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,21 +58,21 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xml: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test_api: 0.4.12 + test_api: 0.4.13 clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -80,4 +80,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 81e4 +# PUBSPEC CHECKSUM: 83e9 diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index b9da642d9b219..73664053651cf 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -18,6 +18,6 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: dc60 +# PUBSPEC CHECKSUM: dd61 diff --git a/dev/integration_tests/web/web/.gitignore b/dev/integration_tests/web/web/.gitignore new file mode 100644 index 0000000000000..8edeffb23f791 --- /dev/null +++ b/dev/integration_tests/web/web/.gitignore @@ -0,0 +1,2 @@ +# This file is generated by a test. It should not be committed to source control. +generated_entrypoint.html diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index 06a7f2dcdf012..0c8362dd84328 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -10,6 +10,6 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: dc60 +# PUBSPEC CHECKSUM: dd61 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 1de931a75d0f9..3f95197d431e0 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,9 +42,9 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,14 +52,14 @@ dev_dependencies: flutter_goldens: sdk: flutter http: 0.13.5 - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,10 +78,10 @@ dev_dependencies: shelf_web_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e3d2 +# PUBSPEC CHECKSUM: 30d7 diff --git a/dev/integration_tests/windows_startup_test/.metadata b/dev/integration_tests/windows_startup_test/.metadata new file mode 100644 index 0000000000000..7ec30051bc232 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + channel: unknown + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: android + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: ios + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: linux + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: macos + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: web + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + - platform: windows + create_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + base_revision: c865207540a1eb960aa89ac61ba89d0f0fa7bd17 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/dev/integration_tests/windows_startup_test/README.md b/dev/integration_tests/windows_startup_test/README.md new file mode 100644 index 0000000000000..28061dde857fa --- /dev/null +++ b/dev/integration_tests/windows_startup_test/README.md @@ -0,0 +1,3 @@ +# Windows start up test + +This test verifies that Flutter draws a frame before the Windows app is shown. \ No newline at end of file diff --git a/dev/integration_tests/windows_startup_test/lib/main.dart b/dev/integration_tests/windows_startup_test/lib/main.dart new file mode 100644 index 0000000000000..e2d5d985aeeaa --- /dev/null +++ b/dev/integration_tests/windows_startup_test/lib/main.dart @@ -0,0 +1,74 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:flutter/services.dart'; +import 'package:flutter_driver/driver_extension.dart'; + +void drawHelloWorld() { + final ui.ParagraphStyle style = ui.ParagraphStyle(); + final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(style) + ..addText('Hello world'); + final ui.Paragraph paragraph = paragraphBuilder.build(); + + paragraph.layout(const ui.ParagraphConstraints(width: 100.0)); + + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + + canvas.drawParagraph(paragraph, ui.Offset.zero); + + final ui.Picture picture = recorder.endRecording(); + final ui.SceneBuilder sceneBuilder = ui.SceneBuilder() + ..addPicture(ui.Offset.zero, picture) + ..pop(); + + ui.window.render(sceneBuilder.build()); +} + +void main() async { + // Create a completer to send the result back to the integration test. + final Completer completer = Completer(); + enableFlutterDriverExtension(handler: (String? message) => completer.future); + + try { + const MethodChannel methodChannel = + MethodChannel('tests.flutter.dev/windows_startup_test'); + + final bool? visible = await methodChannel.invokeMethod('isWindowVisible'); + if (visible == null || visible == true) { + throw 'Window should be hidden at startup'; + } + + bool firstFrame = true; + ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) async { + final bool? visible = await methodChannel.invokeMethod('isWindowVisible'); + if (visible == null) { + throw 'Method channel unavailable'; + } + + if (visible == true) { + if (firstFrame) { + throw 'Window should be hidden on first frame'; + } + + if (!completer.isCompleted) { + completer.complete('success'); + } + } + + // Draw something to trigger the first frame callback that displays the + // window. + drawHelloWorld(); + firstFrame = false; + }; + + ui.PlatformDispatcher.instance.scheduleFrame(); + } catch (e) { + completer.completeError(e); + rethrow; + } +} diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml new file mode 100644 index 0000000000000..18b3afc370299 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -0,0 +1,65 @@ +name: windows_startup_test +description: Integration test for Windows app's startup. + +environment: + sdk: ">=2.17.0-0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_driver: + sdk: flutter + test: 1.21.5 + + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + logging: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + mime: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pub_semver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_packages_handler: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_static: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_web_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_span: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +# PUBSPEC CHECKSUM: 2537 diff --git a/dev/integration_tests/windows_startup_test/test_driver/main_test.dart b/dev/integration_tests/windows_startup_test/test_driver/main_test.dart new file mode 100644 index 0000000000000..f126dc92fb3d4 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/test_driver/main_test.dart @@ -0,0 +1,17 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; + +void main() { + test('Windows app starts and draws frame', () async { + final FlutterDriver driver = await FlutterDriver.connect(printCommunication: true); + final String result = await driver.requestData(null); + + expect(result, equals('success')); + + await driver.close(); + }, timeout: Timeout.none); +} diff --git a/dev/integration_tests/windows_startup_test/windows/.gitignore b/dev/integration_tests/windows_startup_test/windows/.gitignore new file mode 100644 index 0000000000000..d492d0d98c8fd --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/dev/integration_tests/windows_startup_test/windows/CMakeLists.txt b/dev/integration_tests/windows_startup_test/windows/CMakeLists.txt new file mode 100644 index 0000000000000..334308a189d00 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/CMakeLists.txt @@ -0,0 +1,101 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(windows_startup_test LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "windows_startup_test") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt b/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000000..930d2071a324e --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/dev/integration_tests/windows_startup_test/windows/flutter/generated_plugins.cmake b/dev/integration_tests/windows_startup_test/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000000..b93c4c30c1670 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/dev/integration_tests/windows_startup_test/windows/runner/CMakeLists.txt b/dev/integration_tests/windows_startup_test/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000000..17411a8ab8eb7 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/dev/integration_tests/windows_startup_test/windows/runner/Runner.rc b/dev/integration_tests/windows_startup_test/windows/runner/Runner.rc new file mode 100644 index 0000000000000..b2671cacb8c68 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +// IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "windows_startup_test" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "windows_startup_test" "\0" + VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "windows_startup_test.exe" "\0" + VALUE "ProductName", "windows_startup_test" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000000..cb4c30385688f --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.cpp @@ -0,0 +1,95 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter_window.h" + +#include +#include + +#include +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + static std::mutex visible_mutex; + static bool visible = false; + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + std::scoped_lock lock(visible_mutex); + this->Show(); + visible = true; + }); + + // Create a method channel to check the window's visibility. + flutter::MethodChannel<> channel( + flutter_controller_->engine()->messenger(), "tests.flutter.dev/windows_startup_test", + &flutter::StandardMethodCodec::GetInstance()); + + channel.SetMethodCallHandler( + [](const flutter::MethodCall<>& call, + std::unique_ptr> result) { + std::scoped_lock lock(visible_mutex); + if (call.method_name() == "isWindowVisible") { + result->Success(visible); + } else { + result->NotImplemented(); + } + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.h b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.h new file mode 100644 index 0000000000000..bbc5836c018a2 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/flutter_window.h @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/dev/integration_tests/windows_startup_test/windows/runner/main.cpp b/dev/integration_tests/windows_startup_test/windows/runner/main.cpp new file mode 100644 index 0000000000000..2bf0983c00791 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/main.cpp @@ -0,0 +1,48 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"windows_startup_test", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/dev/integration_tests/windows_startup_test/windows/runner/resource.h b/dev/integration_tests/windows_startup_test/windows/runner/resource.h new file mode 100644 index 0000000000000..c245ff19cb580 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/resource.h @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/dev/integration_tests/windows_startup_test/windows/runner/runner.exe.manifest b/dev/integration_tests/windows_startup_test/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000000..a42ea7687cb67 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/dev/integration_tests/windows_startup_test/windows/runner/utils.cpp b/dev/integration_tests/windows_startup_test/windows/runner/utils.cpp new file mode 100644 index 0000000000000..7ae65329f704d --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/utils.cpp @@ -0,0 +1,68 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/dev/integration_tests/windows_startup_test/windows/runner/utils.h b/dev/integration_tests/windows_startup_test/windows/runner/utils.h new file mode 100644 index 0000000000000..54414c989ba71 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/utils.h @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/dev/integration_tests/windows_startup_test/windows/runner/win32_window.cpp b/dev/integration_tests/windows_startup_test/windows/runner/win32_window.cpp new file mode 100644 index 0000000000000..635a5b29f532c --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/win32_window.cpp @@ -0,0 +1,253 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/dev/integration_tests/windows_startup_test/windows/runner/win32_window.h b/dev/integration_tests/windows_startup_test/windows/runner/win32_window.h new file mode 100644 index 0000000000000..b161e9b84b8b3 --- /dev/null +++ b/dev/integration_tests/windows_startup_test/windows/runner/win32_window.h @@ -0,0 +1,103 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/dev/manual_tests/lib/actions.dart b/dev/manual_tests/lib/actions.dart index 385cace542cac..07fdc83fa91b9 100644 --- a/dev/manual_tests/lib/actions.dart +++ b/dev/manual_tests/lib/actions.dart @@ -425,7 +425,7 @@ class _FocusDemoState extends State { debugLabel: 'Scope', autofocus: true, child: DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Scaffold( appBar: AppBar( title: const Text('Actions Demo'), diff --git a/dev/manual_tests/lib/card_collection.dart b/dev/manual_tests/lib/card_collection.dart index 89378491decfb..39e05c628f705 100644 --- a/dev/manual_tests/lib/card_collection.dart +++ b/dev/manual_tests/lib/card_collection.dart @@ -243,7 +243,7 @@ class CardCollectionState extends State { padding: const EdgeInsets.only(left: 72.0), height: 128.0, alignment: const Alignment(-1.0, 0.5), - child: Text('Swipe Away: ${_cardModels.length}', style: Theme.of(context).primaryTextTheme.headline6), + child: Text('Swipe Away: ${_cardModels.length}', style: Theme.of(context).primaryTextTheme.titleLarge), ), ); } @@ -314,7 +314,7 @@ class CardCollectionState extends State { } final ThemeData theme = Theme.of(context); - final TextStyle? backgroundTextStyle = theme.primaryTextTheme.headline6; + final TextStyle? backgroundTextStyle = theme.primaryTextTheme.titleLarge; // The background Widget appears behind the Dismissible card when the card // moves to the left or right. The Positioned widget ensures that the diff --git a/dev/manual_tests/lib/drag_and_drop.dart b/dev/manual_tests/lib/drag_and_drop.dart index e54ab87c1c632..f897cdf8389d3 100644 --- a/dev/manual_tests/lib/drag_and_drop.dart +++ b/dev/manual_tests/lib/drag_and_drop.dart @@ -101,7 +101,7 @@ class ExampleDragSource extends StatelessWidget { } final Widget contents = DefaultTextStyle( - style: Theme.of(context).textTheme.bodyText2!, + style: Theme.of(context).textTheme.bodyMedium!, textAlign: TextAlign.center, child: Dot( color: color, @@ -190,7 +190,7 @@ class MovableBall extends StatelessWidget { @override Widget build(BuildContext context) { final Widget ball = DefaultTextStyle( - style: Theme.of(context).primaryTextTheme.bodyText2!, + style: Theme.of(context).primaryTextTheme.bodyMedium!, textAlign: TextAlign.center, child: Dot( key: kBallKey, diff --git a/dev/manual_tests/lib/focus.dart b/dev/manual_tests/lib/focus.dart index 0b281526a64cf..3b7d23e8b1631 100644 --- a/dev/manual_tests/lib/focus.dart +++ b/dev/manual_tests/lib/focus.dart @@ -138,7 +138,7 @@ class _FocusDemoState extends State { onKey: _handleKeyPress, autofocus: true, child: DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Scaffold( appBar: AppBar( title: const Text('Focus Demo'), diff --git a/dev/manual_tests/lib/hover.dart b/dev/manual_tests/lib/hover.dart index d88c42fc882e5..9992914c31860 100644 --- a/dev/manual_tests/lib/hover.dart +++ b/dev/manual_tests/lib/hover.dart @@ -29,7 +29,7 @@ class _HoverDemoState extends State { ); return DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Scaffold( appBar: AppBar( title: const Text('Hover Demo'), diff --git a/dev/manual_tests/lib/material_arc.dart b/dev/manual_tests/lib/material_arc.dart index 3c1e4b8b4ce18..ccffb75294d81 100644 --- a/dev/manual_tests/lib/material_arc.dart +++ b/dev/manual_tests/lib/material_arc.dart @@ -214,7 +214,7 @@ class _PointDemoState extends State<_PointDemo> { child: Text( 'Tap the refresh button to run the animation. Drag the green ' "and red points to change the animation's path.", - style: Theme.of(context).textTheme.caption?.copyWith(fontSize: 16.0), + style: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 16.0), ), ), ), @@ -382,7 +382,7 @@ class _RectangleDemoState extends State<_RectangleDemo> { child: Text( 'Tap the refresh button to run the animation. Drag the rectangles ' "to change the animation's path.", - style: Theme.of(context).textTheme.caption!.copyWith(fontSize: 16.0), + style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 16.0), ), ), ), diff --git a/dev/manual_tests/lib/raw_keyboard.dart b/dev/manual_tests/lib/raw_keyboard.dart index 52c94dab91cf1..1fbb68f76bfb4 100644 --- a/dev/manual_tests/lib/raw_keyboard.dart +++ b/dev/manual_tests/lib/raw_keyboard.dart @@ -66,12 +66,12 @@ class _HardwareKeyDemoState extends State { onTap: () { _focusNode.requestFocus(); }, - child: Text('Tap to focus', style: textTheme.headline4), + child: Text('Tap to focus', style: textTheme.headlineMedium), ); } if (_event == null) { - return Text('Press a key', style: textTheme.headline4); + return Text('Press a key', style: textTheme.headlineMedium); } final RawKeyEventData? data = _event?.data; @@ -139,7 +139,7 @@ class _HardwareKeyDemoState extends State { } dataText.add(Text(pressed.join(' '))); return DefaultTextStyle( - style: textTheme.subtitle1!, + style: textTheme.titleMedium!, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: dataText, diff --git a/dev/manual_tests/lib/star_border.dart b/dev/manual_tests/lib/star_border.dart index 70e8623b30071..7a4e893badbaa 100644 --- a/dev/manual_tests/lib/star_border.dart +++ b/dev/manual_tests/lib/star_border.dart @@ -80,7 +80,7 @@ class _MyHomePageState extends State { color: Colors.blue.shade100, shape: lerpBorder( StarBorder.polygon( - side: const BorderSide(strokeAlign: StrokeAlign.center, width: 2), + side: const BorderSide(strokeAlign: BorderSide.strokeAlignCenter, width: 2), sides: _model.points, pointRounding: _model.pointRounding, rotation: _model.rotation, @@ -102,7 +102,7 @@ class _MyHomePageState extends State { color: Colors.blue.shade100, shape: lerpBorder( StarBorder( - side: const BorderSide(strokeAlign: StrokeAlign.center, width: 2), + side: const BorderSide(strokeAlign: BorderSide.strokeAlignCenter, width: 2), points: _model.points, innerRadiusRatio: _model.innerRadiusRatio, pointRounding: _model.pointRounding, diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index ccddbcdbf352d..f08a3fa835b84 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -28,9 +28,9 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 50ba +# PUBSPEC CHECKSUM: 76bc diff --git a/dev/manual_tests/windows/runner/flutter_window.cpp b/dev/manual_tests/windows/runner/flutter_window.cpp index 9cbd3109c3fee..f68aa9c26c0f5 100644 --- a/dev/manual_tests/windows/runner/flutter_window.cpp +++ b/dev/manual_tests/windows/runner/flutter_window.cpp @@ -30,6 +30,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/dev/manual_tests/windows/runner/main.cpp b/dev/manual_tests/windows/runner/main.cpp index 5bd83f75abba9..e9efa2edb3f61 100644 --- a/dev/manual_tests/windows/runner/main.cpp +++ b/dev/manual_tests/windows/runner/main.cpp @@ -31,7 +31,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"manual_tests", origin, size)) { + if (!window.Create(L"manual_tests", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/dev/manual_tests/windows/runner/win32_window.cpp b/dev/manual_tests/windows/runner/win32_window.cpp index 4021a2cfd40a1..635a5b29f532c 100644 --- a/dev/manual_tests/windows/runner/win32_window.cpp +++ b/dev/manual_tests/windows/runner/win32_window.cpp @@ -106,9 +106,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -121,7 +121,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -133,6 +133,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, diff --git a/dev/manual_tests/windows/runner/win32_window.h b/dev/manual_tests/windows/runner/win32_window.h index 1dab1777c4950..b161e9b84b8b3 100644 --- a/dev/manual_tests/windows/runner/win32_window.h +++ b/dev/manual_tests/windows/runner/win32_window.h @@ -32,15 +32,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart index 28e95c179c3e1..0fde6bf4b45db 100644 --- a/dev/tools/dartdoc.dart +++ b/dev/tools/dartdoc.dart @@ -255,7 +255,7 @@ ArgParser _createArgsParser() { help: 'Show command help.'); parser.addFlag('verbose', defaultsTo: true, help: 'Whether to report all error messages (on) or attempt to ' - 'filter out some known false positives (off). Shut this off ' + 'filter out some known false positives (off). Shut this off ' 'locally if you want to address Flutter-specific issues.'); parser.addFlag('checked', abbr: 'c', help: 'Run dartdoc in checked mode.'); @@ -433,7 +433,7 @@ void sanityCheckDocs() { // Check a "snippet" example, any one will do. final File snippetExample = File('$kPublishRoot/api/widgets/ModalRoute/barrierColor.html'); - final RegExp snippetRegExp = RegExp(r'\s*
.*Color get barrierColor => Theme\.of\(navigator\.context\)\.backgroundColor;.*
'); + final RegExp snippetRegExp = RegExp(r'\s*
.*Color get barrierColor => Theme\.of\(navigator\.context\)\.colorScheme.background;.*
'); _sanityCheckExample(snippetExample, snippetRegExp); // Check a "dartpad" example, any one will do. diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index 7651bfdc9443a..659cec641f918 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.dart @@ -17,15 +17,17 @@ import 'dart:convert'; import 'dart:io'; +import 'package:gen_defaults/action_chip_template.dart'; import 'package:gen_defaults/app_bar_template.dart'; +import 'package:gen_defaults/banner_template.dart'; import 'package:gen_defaults/button_template.dart'; import 'package:gen_defaults/card_template.dart'; -import 'package:gen_defaults/chip_action_template.dart'; -import 'package:gen_defaults/chip_filter_template.dart'; -import 'package:gen_defaults/chip_input_template.dart'; +import 'package:gen_defaults/checkbox_template.dart'; import 'package:gen_defaults/dialog_template.dart'; import 'package:gen_defaults/fab_template.dart'; +import 'package:gen_defaults/filter_chip_template.dart'; import 'package:gen_defaults/icon_button_template.dart'; +import 'package:gen_defaults/input_chip_template.dart'; import 'package:gen_defaults/input_decorator_template.dart'; import 'package:gen_defaults/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_rail_template.dart'; @@ -102,14 +104,18 @@ Future main(List args) async { tokens['colorsDark'] = _readTokenFile('color_dark.json'); AppBarTemplate('AppBar', '$materialLib/app_bar.dart', tokens).updateFile(); + BannerTemplate('Banner', '$materialLib/banner.dart', tokens).updateFile(); ButtonTemplate('md.comp.elevated-button', 'ElevatedButton', '$materialLib/elevated_button.dart', tokens).updateFile(); + ButtonTemplate('md.comp.filled-button', 'FilledButton', '$materialLib/filled_button.dart', tokens).updateFile(); + ButtonTemplate('md.comp.filled-tonal-button', 'FilledTonalButton', '$materialLib/filled_button.dart', tokens).updateFile(); ButtonTemplate('md.comp.outlined-button', 'OutlinedButton', '$materialLib/outlined_button.dart', tokens).updateFile(); ButtonTemplate('md.comp.text-button', 'TextButton', '$materialLib/text_button.dart', tokens).updateFile(); CardTemplate('Card', '$materialLib/card.dart', tokens).updateFile(); - ChipActionTemplate('ActionChip', '$materialLib/chip_action.dart', tokens).updateFile(); - ChipFilterTemplate('FilterChip', '$materialLib/chip_filter.dart', tokens).updateFile(); - ChipFilterTemplate('FilterChip', '$materialLib/chip_choice.dart', tokens).updateFile(); - ChipInputTemplate('InputChip', '$materialLib/chip_input.dart', tokens).updateFile(); + CheckboxTemplate('Checkbox', '$materialLib/checkbox.dart', tokens).updateFile(); + ChipActionTemplate('ActionChip', '$materialLib/action_chip.dart', tokens).updateFile(); + ChipFilterTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile(); + ChipFilterTemplate('FilterChip', '$materialLib/choice_chip.dart', tokens).updateFile(); + ChipInputTemplate('InputChip', '$materialLib/input_chip.dart', tokens).updateFile(); DialogTemplate('Dialog', '$materialLib/dialog.dart', tokens).updateFile(); FABTemplate('FAB', '$materialLib/floating_action_button.dart', tokens).updateFile(); IconButtonTemplate('IconButton', '$materialLib/icon_button.dart', tokens).updateFile(); diff --git a/dev/tools/gen_defaults/lib/chip_action_template.dart b/dev/tools/gen_defaults/lib/action_chip_template.dart similarity index 100% rename from dev/tools/gen_defaults/lib/chip_action_template.dart rename to dev/tools/gen_defaults/lib/action_chip_template.dart diff --git a/dev/tools/gen_defaults/lib/app_bar_template.dart b/dev/tools/gen_defaults/lib/app_bar_template.dart index f426430df713f..6df3f5dbebdfc 100644 --- a/dev/tools/gen_defaults/lib/app_bar_template.dart +++ b/dev/tools/gen_defaults/lib/app_bar_template.dart @@ -49,7 +49,7 @@ class _${blockName}DefaultsM3 extends AppBarTheme { ); @override - TextStyle? get toolbarTextStyle => _textTheme.bodyText2; + TextStyle? get toolbarTextStyle => _textTheme.bodyMedium; @override TextStyle? get titleTextStyle => ${textStyle('md.comp.top-app-bar.small.headline')}; diff --git a/dev/tools/gen_defaults/lib/banner_template.dart b/dev/tools/gen_defaults/lib/banner_template.dart new file mode 100644 index 0000000000000..123c8ec103431 --- /dev/null +++ b/dev/tools/gen_defaults/lib/banner_template.dart @@ -0,0 +1,31 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'template.dart'; + +class BannerTemplate extends TokenTemplate { + const BannerTemplate(super.blockName, super.fileName, super.tokens); + + @override + String generate() => ''' +class _${blockName}DefaultsM3 extends MaterialBannerThemeData { + const _${blockName}DefaultsM3(this.context) + : super(elevation: ${elevation("md.comp.banner.container")}); + + final BuildContext context; + + @override + Color? get backgroundColor => ${componentColor("md.comp.banner.container")}; + + @override + Color? get surfaceTintColor => ${color("md.comp.banner.container.surface-tint-layer.color")}; + + @override + Color? get dividerColor => ${color("md.comp.banner.divider.color")}; + + @override + TextStyle? get contentTextStyle => ${textStyle("md.comp.banner.supporting-text")}; +} +'''; +} diff --git a/dev/tools/gen_defaults/lib/checkbox_template.dart b/dev/tools/gen_defaults/lib/checkbox_template.dart new file mode 100644 index 0000000000000..2bfeaac99609e --- /dev/null +++ b/dev/tools/gen_defaults/lib/checkbox_template.dart @@ -0,0 +1,119 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'template.dart'; + +class CheckboxTemplate extends TokenTemplate { + const CheckboxTemplate(super.blockName, super.fileName, super.tokens, { + super.colorSchemePrefix = '_colors.', + }); + + @override + String generate() => ''' +class _${blockName}DefaultsM3 extends CheckboxThemeData { + _${blockName}DefaultsM3(BuildContext context) + : _theme = Theme.of(context), + _colors = Theme.of(context).colorScheme; + + final ThemeData _theme; + final ColorScheme _colors; + + @override + MaterialStateProperty get fillColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + if (states.contains(MaterialState.selected)) { + return ${componentColor('md.comp.checkbox.selected.disabled.container')}; + } + return ${componentColor('md.comp.checkbox.unselected.disabled.outline')}.withOpacity(${opacity('md.comp.checkbox.unselected.disabled.container.opacity')}); + } + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return ${componentColor('md.comp.checkbox.selected.pressed.container')}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.checkbox.selected.hover.container')}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor('md.comp.checkbox.selected.focus.container')}; + } + return ${componentColor('md.comp.checkbox.selected.container')}; + } + if (states.contains(MaterialState.pressed)) { + return ${componentColor('md.comp.checkbox.unselected.pressed.outline')}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.checkbox.unselected.hover.outline')}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor('md.comp.checkbox.unselected.focus.outline')}; + } + return ${componentColor('md.comp.checkbox.unselected.outline')}; + }); + } + + @override + MaterialStateProperty get checkColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + if (states.contains(MaterialState.selected)) { + return ${componentColor('md.comp.checkbox.selected.disabled.icon')}; + } + return Colors.transparent; // No icons available when the checkbox is unselected. + } + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return ${componentColor('md.comp.checkbox.selected.pressed.icon')}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.checkbox.selected.hover.icon')}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor('md.comp.checkbox.selected.focus.icon')}; + } + return ${componentColor('md.comp.checkbox.selected.icon')}; + } + return Colors.transparent; // No icons available when the checkbox is unselected. + }); + } + + @override + MaterialStateProperty get overlayColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return ${componentColor('md.comp.checkbox.selected.pressed.state-layer')}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.checkbox.selected.hover.state-layer')}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor('md.comp.checkbox.selected.focus.state-layer')}; + } + return Colors.transparent; + } + if (states.contains(MaterialState.pressed)) { + return ${componentColor('md.comp.checkbox.unselected.pressed.state-layer')}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor('md.comp.checkbox.unselected.hover.state-layer')}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor('md.comp.checkbox.unselected.focus.state-layer')}; + } + return Colors.transparent; + }); + } + + @override + double get splashRadius => ${tokens['md.comp.checkbox.state-layer.size']} / 2; + + @override + MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize; + + @override + VisualDensity get visualDensity => _theme.visualDensity; +} +'''; +} diff --git a/dev/tools/gen_defaults/lib/chip_filter_template.dart b/dev/tools/gen_defaults/lib/filter_chip_template.dart similarity index 100% rename from dev/tools/gen_defaults/lib/chip_filter_template.dart rename to dev/tools/gen_defaults/lib/filter_chip_template.dart diff --git a/dev/tools/gen_defaults/lib/chip_input_template.dart b/dev/tools/gen_defaults/lib/input_chip_template.dart similarity index 100% rename from dev/tools/gen_defaults/lib/chip_input_template.dart rename to dev/tools/gen_defaults/lib/input_chip_template.dart diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index e44741063fa34..0212c5e76462d 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: dev_dependencies: path: 1.8.2 - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,8 +20,8 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,13 +46,13 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4304 +# PUBSPEC CHECKSUM: 3908 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 8720258f0d221..68057f385e546 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -20,17 +20,17 @@ dependencies: typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 - test_api: 0.4.12 + test: 1.21.5 + test_api: 0.4.13 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -50,11 +50,11 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 81f9 +# PUBSPEC CHECKSUM: 77fd diff --git a/dev/tools/generate_android_spline_data.dart b/dev/tools/generate_android_spline_data.dart new file mode 100644 index 0000000000000..12e79d5866096 --- /dev/null +++ b/dev/tools/generate_android_spline_data.dart @@ -0,0 +1,61 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const int _nbSamples = 100; +final List _splinePosition = List.filled(_nbSamples + 1, 0.0); +final List _splineTime = List.filled(_nbSamples + 1, 0.0); +const double _startTension = 0.5; +const double _endTension = 1.0; +const double _inflexion = 0.35; + +// Generate the spline data used in ClampingScrollSimulation. +// +// This logic is a translation of the 2-dimensional logic found in +// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/Scroller.java. +// +// The output of this program should be copied over to [_splinePosition] in +// flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart. +void main() { + const double p1 = _startTension * _inflexion; + const double p2 = 1.0 - _endTension * (1.0 - _inflexion); + double xMin = 0.0; + double yMin = 0.0; + for (int i = 0; i < _nbSamples; i++) { + final double alpha = i / _nbSamples; + double xMax = 1.0; + double x, tx, coef; + while (true) { + x = xMin + (xMax - xMin) / 2.0; + coef = 3.0 * x * (1.0 - x); + tx = coef * ((1.0 - x) * p1 + x * p2) + x * x * x; + if ((tx - alpha).abs() < 1e-5) { + break; + } + if (tx > alpha) { + xMax = x; + } else { + xMin = x; + } + } + _splinePosition[i] = coef * ((1.0 - x) * _startTension + x) + x * x * x; + double yMax = 1.0; + double y, dy; + while (true) { + y = yMin + (yMax - yMin) / 2.0; + coef = 3.0 * y * (1.0 - y); + dy = coef * ((1.0 - y) * _startTension + y) + y * y * y; + if ((dy - alpha).abs() < 1e-5) { + break; + } + if (dy > alpha) { + yMax = y; + } else { + yMin = y; + } + } + _splineTime[i] = coef * ((1.0 - y) * p1 + y * p2) + y * y * y; + } + _splinePosition[_nbSamples] = _splineTime[_nbSamples] = 1.0; + print(_splinePosition); +} diff --git a/dev/tools/localization/bin/gen_subtag_registry.dart b/dev/tools/localization/bin/gen_subtag_registry.dart index c2779bfc7119a..5205432c272af 100644 --- a/dev/tools/localization/bin/gen_subtag_registry.dart +++ b/dev/tools/localization/bin/gen_subtag_registry.dart @@ -7,8 +7,8 @@ import 'dart:io'; const String registry = 'https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry'; -/// A script to generate a Dart cache of https://www.iana.org. This should be -/// run occasionally. It was created since iana.org was found to be flakey. +/// A script to generate a Dart cache of https://www.iana.org. This should be +/// run occasionally. It was created since iana.org was found to be flakey. /// /// To execute: dart gen_subtag_registry.dart > language_subtag_registry.dart Future main() async { diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index e4af4ee6bc18b..fe209b869c194 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,15 +26,15 @@ dependencies: typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 - test_api: 0.4.12 + test: 1.21.5 + test_api: 0.4.13 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,11 +54,11 @@ dev_dependencies: source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4611 +# PUBSPEC CHECKSUM: a415 diff --git a/dev/tools/update_icons.dart b/dev/tools/update_icons.dart index 41bf6745e0f10..1d03247456ee4 100644 --- a/dev/tools/update_icons.dart +++ b/dev/tools/update_icons.dart @@ -18,6 +18,7 @@ const String _iconsTemplatePathOption = 'icons-template'; const String _newCodepointsPathOption = 'new-codepoints'; const String _oldCodepointsPathOption = 'old-codepoints'; const String _fontFamilyOption = 'font-family'; +const String _classNameOption = 'class-name'; const String _enforceSafetyChecks = 'enforce-safety-checks'; const String _dryRunOption = 'dry-run'; @@ -25,6 +26,7 @@ const String _defaultIconsPath = 'packages/flutter/lib/src/material/icons.dart'; const String _defaultNewCodepointsPath = 'codepoints'; const String _defaultOldCodepointsPath = 'bin/cache/artifacts/material_fonts/codepoints'; const String _defaultFontFamily = 'MaterialIcons'; +const String _defaultClassName = 'Icons'; const String _defaultDemoFilePath = '/tmp/new_icons_demo.dart'; const String _beginGeneratedMark = '// BEGIN GENERATED ICONS'; @@ -211,6 +213,7 @@ void main(List args) { iconsTemplateContents, newTokenPairMap, argResults[_fontFamilyOption] as String, + argResults[_classNameOption] as String, argResults[_enforceSafetyChecks] as bool, ); @@ -245,6 +248,9 @@ ArgResults _handleArguments(List args) { ..addOption(_fontFamilyOption, defaultsTo: _defaultFontFamily, help: 'The font family to use for the IconData constants') + ..addOption(_classNameOption, + defaultsTo: _defaultClassName, + help: 'The containing class for all icons') ..addFlag(_enforceSafetyChecks, defaultsTo: true, help: 'Whether to exit if safety checks fail (e.g. codepoints are missing or unstable') @@ -280,10 +286,12 @@ String _regenerateIconsFile( String templateFileContents, Map tokenPairMap, String fontFamily, + String className, bool enforceSafetyChecks, ) { final List newIcons = tokenPairMap.entries - .map((MapEntry entry) => Icon(entry, fontFamily: fontFamily)) + .map((MapEntry entry) => + Icon(entry, fontFamily: fontFamily, className: className)) .toList(); newIcons.sort((Icon a, Icon b) => a._compareTo(b)); @@ -309,7 +317,8 @@ String _regenerateIconsFile( final Icon iOSIcon = newIcons.firstWhere( (Icon icon) => icon.id == '${ids[1]}$style', orElse: () => throw ids[1]); - platformAdaptiveDeclarations.add(Icon.platformAdaptiveDeclaration('$flutterId$style', agnosticIcon, iOSIcon), + platformAdaptiveDeclarations.add( + agnosticIcon.platformAdaptiveDeclaration('$flutterId$style', iOSIcon), ); } catch (e) { if (style == '') { @@ -433,7 +442,10 @@ void _generateIconDemo(File demoFilePath, Map tokenPairMap) { class Icon { // Parse tokenPair (e.g. {"6_ft_apart_outlined": "e004"}). - Icon(MapEntry tokenPair, {this.fontFamily = _defaultFontFamily}) { + Icon(MapEntry tokenPair, { + this.fontFamily = _defaultFontFamily, + this.className = _defaultClassName, + }) { id = tokenPair.key; hexCodepoint = tokenPair.value; @@ -485,6 +497,7 @@ class Icon { late String hexCodepoint; // e.g. e547 late String htmlSuffix = ''; // The suffix for the 'material-icons' HTML class. String fontFamily; // The IconData font family. + String className; // The containing class. String get name => shortId.replaceAll('_', ' ').trim(); @@ -493,7 +506,7 @@ class Icon { String get dartDoc => '$shortId — $family icon named "$name"$style'; - String get usage => 'Icon(Icons.$flutterId),'; + String get usage => 'Icon($className.$flutterId),'; String get mirroredInRTL => _iconsMirroredWhenRTL.contains(shortId) ? ', matchTextDirection: true' @@ -508,10 +521,10 @@ class Icon { $declaration '''; - static String platformAdaptiveDeclaration(String fullFlutterId, Icon agnosticIcon, Icon iOSIcon) => ''' + String platformAdaptiveDeclaration(String fullFlutterId, Icon iOSIcon) => ''' - /// Platform-adaptive icon for ${agnosticIcon.dartDoc} and ${iOSIcon.dartDoc}.; - IconData get $fullFlutterId => !_isCupertino() ? Icons.${agnosticIcon.flutterId} : Icons.${iOSIcon.flutterId}; + /// Platform-adaptive icon for $dartDoc and ${iOSIcon.dartDoc}.; + IconData get $fullFlutterId => !_isCupertino() ? $className.$flutterId : $className.${iOSIcon.flutterId}; '''; @override diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index bc7579976a6ea..c78059fecf262 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: flutter: sdk: flutter args: 2.3.1 - vector_math: 2.1.2 + vector_math: 2.1.3 xml: 6.1.0 characters: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,6 +34,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: db5b +# PUBSPEC CHECKSUM: 2a5d diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 6b952c0f7e453..d0991082ddd1f 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -31,6 +31,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3945 +# PUBSPEC CHECKSUM: a347 diff --git a/examples/api/lib/animation/curves/curve2_d.0.dart b/examples/api/lib/animation/curves/curve2_d.0.dart index 98b89dc5c9669..7ac5261ecfbaf 100644 --- a/examples/api/lib/animation/curves/curve2_d.0.dart +++ b/examples/api/lib/animation/curves/curve2_d.0.dart @@ -71,7 +71,7 @@ class _FollowCurve2DState extends State super.initState(); controller = AnimationController(duration: widget.duration, vsync: this); animation = CurvedAnimation(parent: controller, curve: widget.curve); - // Have the controller repeat indefinitely. If you want it to "bounce" back + // Have the controller repeat indefinitely. If you want it to "bounce" back // and forth, set the reverse parameter to true. controller.repeat(); controller.addListener(() => setState(() {})); @@ -110,7 +110,7 @@ class MyStatelessWidget extends StatelessWidget { child: CircleAvatar( backgroundColor: Colors.yellow, child: DefaultTextStyle( - style: Theme.of(context).textTheme.headline6!, + style: Theme.of(context).textTheme.titleLarge!, child: const Text('B'), // Buzz, buzz! ), ), diff --git a/examples/api/lib/material/about/about_list_tile.0.dart b/examples/api/lib/material/about/about_list_tile.0.dart index 5c21fd00112f6..15859f2c60a63 100644 --- a/examples/api/lib/material/about/about_list_tile.0.dart +++ b/examples/api/lib/material/about/about_list_tile.0.dart @@ -28,7 +28,7 @@ class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final TextStyle textStyle = theme.textTheme.bodyText2!; + final TextStyle textStyle = theme.textTheme.bodyMedium!; final List aboutBoxChildren = [ const SizedBox(height: 24), RichText( diff --git a/examples/api/lib/material/button_style/button_style.0.dart b/examples/api/lib/material/button_style/button_style.0.dart index 7f40de2cc0006..c77fdd207c6f6 100644 --- a/examples/api/lib/material/button_style/button_style.0.dart +++ b/examples/api/lib/material/button_style/button_style.0.dart @@ -58,31 +58,9 @@ class ButtonTypesGroup extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton(onPressed: onPressed, child: const Text('Elevated')), - - // Use an ElevatedButton with specific style to implement the - // 'Filled' type. - ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.onPrimary, - backgroundColor: Theme.of(context).colorScheme.primary, - ).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), - onPressed: onPressed, - child: const Text('Filled'), - ), - - // Use an ElevatedButton with specific style to implement the - // 'Filled Tonal' type. - ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, - ).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), - onPressed: onPressed, - child: const Text('Filled Tonal'), - ), - + FilledButton(onPressed: onPressed, child: const Text('Filled')), + FilledButton.tonal(onPressed: onPressed, child: const Text('Filled Tonal')), OutlinedButton(onPressed: onPressed, child: const Text('Outlined')), - TextButton(onPressed: onPressed, child: const Text('Text')), ], ), diff --git a/examples/api/lib/material/card/card.1.dart b/examples/api/lib/material/card/card.1.dart index 9e9c3d711d11a..ae4761456f428 100644 --- a/examples/api/lib/material/card/card.1.dart +++ b/examples/api/lib/material/card/card.1.dart @@ -32,6 +32,11 @@ class MyStatelessWidget extends StatelessWidget { Widget build(BuildContext context) { return Center( child: Card( + // clipBehavior is necessary because, without it, the InkWell's animation + // will extend beyond the rounded edges of the [Card] (see https://github.com/flutter/flutter/issues/109776) + // This comes with a small performance cost, and you should not set [clipBehavior] + // unless you need it. + clipBehavior: Clip.hardEdge, child: InkWell( splashColor: Colors.blue.withAlpha(30), onTap: () { diff --git a/examples/api/lib/material/divider/divider.0.dart b/examples/api/lib/material/divider/divider.0.dart index 3c76370288d28..604b0d7c2425f 100644 --- a/examples/api/lib/material/divider/divider.0.dart +++ b/examples/api/lib/material/divider/divider.0.dart @@ -56,7 +56,7 @@ class MyStatelessWidget extends StatelessWidget { alignment: AlignmentDirectional.centerStart, child: Text( 'Subheader', - style: Theme.of(context).textTheme.caption, + style: Theme.of(context).textTheme.bodySmall, textAlign: TextAlign.start, ), ), diff --git a/examples/api/lib/material/filled_button/filled_button.0.dart b/examples/api/lib/material/filled_button/filled_button.0.dart new file mode 100644 index 0000000000000..5c58f79ef406c --- /dev/null +++ b/examples/api/lib/material/filled_button/filled_button.0.dart @@ -0,0 +1,61 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flutter code sample for FilledButton + +import 'package:flutter/material.dart'; + +void main() { + runApp(const FilledButtonApp()); +} + +class FilledButtonApp extends StatelessWidget { + const FilledButtonApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true), + home: Scaffold( + appBar: AppBar(title: const Text('FilledButton Sample')), + body: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Column(children: [ + const SizedBox(height: 30), + const Text('Filled'), + const SizedBox(height: 15), + FilledButton( + onPressed: () {}, + child: const Text('Enabled'), + ), + const SizedBox(height: 30), + const FilledButton( + onPressed: null, + child: Text('Disabled'), + ), + ]), + const SizedBox(width: 30), + Column(children: [ + const SizedBox(height: 30), + const Text('Filled tonal'), + const SizedBox(height: 15), + FilledButton.tonal( + onPressed: () {}, + child: const Text('Enabled'), + ), + const SizedBox(height: 30), + const FilledButton.tonal( + onPressed: null, + child: Text('Disabled'), + ), + ]) + ], + ), + ), + ), + ); + } +} diff --git a/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart b/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart index af6df226549bd..e7b0782339a45 100644 --- a/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart +++ b/examples/api/lib/material/input_decorator/input_decoration.floating_label_style_error.0.dart @@ -41,7 +41,7 @@ class InputDecoratorExample extends StatelessWidget { // is in its error state. floatingLabelStyle: MaterialStateTextStyle.resolveWith( (Set states) { - final Color color = states.contains(MaterialState.error) ? Theme.of(context).errorColor: Colors.orange; + final Color color = states.contains(MaterialState.error) ? Theme.of(context).colorScheme.error: Colors.orange; return TextStyle(color: color, letterSpacing: 1.3); } ), diff --git a/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart b/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart index cb4fd6c933e9a..44ad6ba1983d4 100644 --- a/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart +++ b/examples/api/lib/material/input_decorator/input_decoration.label_style_error.0.dart @@ -41,7 +41,7 @@ class InputDecoratorExample extends StatelessWidget { // is in its error state. labelStyle: MaterialStateTextStyle.resolveWith( (Set states) { - final Color color = states.contains(MaterialState.error) ? Theme.of(context).errorColor: Colors.orange; + final Color color = states.contains(MaterialState.error) ? Theme.of(context).colorScheme.error: Colors.orange; return TextStyle(color: color, letterSpacing: 1.3); } ), diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart index 865ce7984ebc2..568301b363acb 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart @@ -33,12 +33,12 @@ class RootPage extends StatelessWidget { @override Widget build(BuildContext context) { - final TextStyle headline5 = Theme.of(context).textTheme.headline5!; + final TextStyle headlineSmall = Theme.of(context).textTheme.headlineSmall!; final ButtonStyle buttonStyle = ElevatedButton.styleFrom( backgroundColor: destination.color, visualDensity: VisualDensity.comfortable, padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), - textStyle: headline5, + textStyle: headlineSmall, ); return Scaffold( @@ -97,7 +97,7 @@ class RootPage extends StatelessWidget { child: Text( '${destination.title} BottomSheet\n' 'Tap the back button to dismiss', - style: headline5, + style: headlineSmall, softWrap: true, textAlign: TextAlign.center, ), @@ -127,7 +127,7 @@ class ListPage extends StatelessWidget { final ButtonStyle buttonStyle = OutlinedButton.styleFrom( foregroundColor: destination.color, fixedSize: const Size.fromHeight(128), - textStyle: Theme.of(context).textTheme.headline5, + textStyle: Theme.of(context).textTheme.headlineSmall, ); return Scaffold( appBar: AppBar( @@ -198,7 +198,7 @@ class _TextPageState extends State { alignment: Alignment.center, child: TextField( controller: textController, - style: theme.primaryTextTheme.headline4?.copyWith( + style: theme.primaryTextTheme.headlineMedium?.copyWith( color: widget.destination.color, ), decoration: InputDecoration( diff --git a/examples/api/lib/material/progress_indicator/circular_progress_indicator.0.dart b/examples/api/lib/material/progress_indicator/circular_progress_indicator.0.dart index ba9211bc96bb1..b5946406f5a7e 100644 --- a/examples/api/lib/material/progress_indicator/circular_progress_indicator.0.dart +++ b/examples/api/lib/material/progress_indicator/circular_progress_indicator.0.dart @@ -62,7 +62,7 @@ class _MyStatefulWidgetState extends State children: [ Text( 'Circular progress indicator with a fixed color', - style: Theme.of(context).textTheme.headline6, + style: Theme.of(context).textTheme.titleLarge, ), CircularProgressIndicator( value: controller.value, diff --git a/examples/api/lib/material/scaffold/scaffold_messenger.of.1.dart b/examples/api/lib/material/scaffold/scaffold_messenger.of.1.dart index b0bd2901d1871..dd3afca9347f8 100644 --- a/examples/api/lib/material/scaffold/scaffold_messenger.of.1.dart +++ b/examples/api/lib/material/scaffold/scaffold_messenger.of.1.dart @@ -46,7 +46,7 @@ class _MyAppState extends State { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/examples/api/lib/material/slider/slider.1.dart b/examples/api/lib/material/slider/slider.1.dart new file mode 100644 index 0000000000000..2e0af68521e89 --- /dev/null +++ b/examples/api/lib/material/slider/slider.1.dart @@ -0,0 +1,66 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flutter code sample for Slider + +import 'package:flutter/material.dart'; + +void main() => runApp(const MyApp()); + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + static const String _title = 'Flutter Code Sample'; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: _title, + home: Scaffold( + appBar: AppBar(title: const Text(_title)), + body: const MyStatefulWidget(), + ), + ); + } +} + +class MyStatefulWidget extends StatefulWidget { + const MyStatefulWidget({super.key}); + + @override + State createState() => _MyStatefulWidgetState(); +} + +class _MyStatefulWidgetState extends State { + double _currentSliderPrimaryValue = 0.2; + double _currentSliderSecondaryValue = 0.5; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Slider( + value: _currentSliderPrimaryValue, + secondaryTrackValue: _currentSliderSecondaryValue, + label: _currentSliderPrimaryValue.round().toString(), + onChanged: (double value) { + setState(() { + _currentSliderPrimaryValue = value; + }); + }, + ), + Slider( + value: _currentSliderSecondaryValue, + label: _currentSliderSecondaryValue.round().toString(), + onChanged: (double value) { + setState(() { + _currentSliderSecondaryValue = value; + }); + }, + ), + ], + ); + } +} diff --git a/examples/api/lib/material/tab_controller/tab_controller.1.dart b/examples/api/lib/material/tab_controller/tab_controller.1.dart index 894f39029dbba..2828af5c8bdcf 100644 --- a/examples/api/lib/material/tab_controller/tab_controller.1.dart +++ b/examples/api/lib/material/tab_controller/tab_controller.1.dart @@ -56,7 +56,7 @@ class MyStatelessWidget extends StatelessWidget { return Center( child: Text( '${tab.text!} Tab', - style: Theme.of(context).textTheme.headline5, + style: Theme.of(context).textTheme.headlineSmall, ), ); }).toList(), diff --git a/examples/api/lib/material/text_field/text_field.2.dart b/examples/api/lib/material/text_field/text_field.2.dart index 33791deb7e778..b6a83d8871328 100644 --- a/examples/api/lib/material/text_field/text_field.2.dart +++ b/examples/api/lib/material/text_field/text_field.2.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flutter code sample for Material Design 3 TextFields. +// Flutter code sample for Material Design 3 TextFields. import 'package:flutter/material.dart'; diff --git a/examples/api/lib/material/theme/theme_extension.1.dart b/examples/api/lib/material/theme/theme_extension.1.dart index 6a6cef5a44615..69f6923d3aaa0 100644 --- a/examples/api/lib/material/theme/theme_extension.1.dart +++ b/examples/api/lib/material/theme/theme_extension.1.dart @@ -26,7 +26,7 @@ class MyColors extends ThemeExtension { } @override - MyColors lerp(ThemeExtension? other, double t) { + MyColors lerp(MyColors? other, double t) { if (other is! MyColors) { return this; } diff --git a/examples/api/lib/material/toggle_buttons/toggle_buttons.0.dart b/examples/api/lib/material/toggle_buttons/toggle_buttons.0.dart index ed595b3c9f826..c7ebf2c3db323 100644 --- a/examples/api/lib/material/toggle_buttons/toggle_buttons.0.dart +++ b/examples/api/lib/material/toggle_buttons/toggle_buttons.0.dart @@ -68,7 +68,7 @@ class _ToggleButtonsSampleState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ // ToggleButtons with a single selection. - Text('Single-select', style: theme.textTheme.subtitle2), + Text('Single-select', style: theme.textTheme.titleSmall), const SizedBox(height: 5), ToggleButtons( direction: vertical ? Axis.vertical : Axis.horizontal, @@ -94,7 +94,7 @@ class _ToggleButtonsSampleState extends State { ), const SizedBox(height: 20), // ToggleButtons with a multiple selection. - Text('Multi-select', style: theme.textTheme.subtitle2), + Text('Multi-select', style: theme.textTheme.titleSmall), const SizedBox(height: 5), ToggleButtons( direction: vertical ? Axis.vertical : Axis.horizontal, @@ -119,7 +119,7 @@ class _ToggleButtonsSampleState extends State { ), const SizedBox(height: 20), // ToggleButtons with icons only. - Text('Icon-only', style: theme.textTheme.subtitle2), + Text('Icon-only', style: theme.textTheme.titleSmall), const SizedBox(height: 5), ToggleButtons( direction: vertical ? Axis.vertical : Axis.horizontal, diff --git a/examples/api/lib/painting/borders/border_side.stroke_align.0.dart b/examples/api/lib/painting/borders/border_side.stroke_align.0.dart new file mode 100644 index 0000000000000..0158f1c75e409 --- /dev/null +++ b/examples/api/lib/painting/borders/border_side.stroke_align.0.dart @@ -0,0 +1,204 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Flutter code sample for [BorderSide.strokeAlign]. + +import 'package:flutter/material.dart'; + +void main() => runApp(const StrokeAlignApp()); + +class StrokeAlignApp extends StatelessWidget { + const StrokeAlignApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp(home: StrokeAlignExample()); + } +} + +class StrokeAlignExample extends StatefulWidget { + const StrokeAlignExample({super.key}); + + @override + State createState() => _StrokeAlignExampleState(); +} + +class _StrokeAlignExampleState extends State + with TickerProviderStateMixin { + late final AnimationController animation; + + @override + void initState() { + super.initState(); + animation = + AnimationController(vsync: this, duration: const Duration(seconds: 1)); + animation.repeat(reverse: true); + animation.addListener(_markDirty); + } + + @override + void dispose() { + animation.dispose(); + super.dispose(); + } + + void _markDirty() { + setState(() {}); + } + + static const double borderWidth = 10; + static const double cornerRadius = 10; + static const Color borderColor = Color(0x8000b4fc); + + @override + Widget build(BuildContext context) { + return Material( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + BorderedBox( + shape: StadiumBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + BorderedBox( + shape: CircleBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + BorderedBox( + shape: OvalBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + BorderedBox( + shape: BeveledRectangleBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + BorderedBox( + shape: BeveledRectangleBorder( + borderRadius: BorderRadius.circular(cornerRadius), + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + BorderedBox( + shape: RoundedRectangleBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + BorderedBox( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(cornerRadius), + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + BorderedBox( + shape: StarBorder( + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + BorderedBox( + shape: StarBorder( + pointRounding: 1, + innerRadiusRatio: 0.5, + points: 8, + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + BorderedBox( + shape: StarBorder.polygon( + sides: 6, + pointRounding: 0.5, + side: BorderSide( + color: borderColor, + width: borderWidth, + strokeAlign: (animation.value * 2) - 1, + ), + ), + ), + ], + ), + ], + ), + ), + ); + } +} + +class BorderedBox extends StatelessWidget { + const BorderedBox({ + super.key, + required this.shape, + }); + + final ShapeBorder shape; + + @override + Widget build(BuildContext context) { + return Container( + width: 100, + height: 50, + decoration: ShapeDecoration( + color: const Color(0xff012677), + shape: shape, + ), + ); + } +} diff --git a/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart b/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart index b20b00240bc5e..7f83e75134a1b 100644 --- a/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart +++ b/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart @@ -70,7 +70,7 @@ class _MyKeyExampleState extends State { color: Colors.white, alignment: Alignment.center, child: DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Focus( focusNode: _focusNode, onKey: _handleKeyEvent, diff --git a/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart b/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart index 282e413e8eaab..f5dc0d6199b72 100644 --- a/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart +++ b/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart @@ -70,7 +70,7 @@ class _MyPhysicalKeyExampleState extends State { color: Colors.white, alignment: Alignment.center, child: DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Focus( focusNode: _focusNode, onKey: _handleKeyEvent, diff --git a/examples/api/lib/widgets/actions/action.action_overridable.0.dart b/examples/api/lib/widgets/actions/action.action_overridable.0.dart index 0844c4669f535..b88b163e43e86 100644 --- a/examples/api/lib/widgets/actions/action.action_overridable.0.dart +++ b/examples/api/lib/widgets/actions/action.action_overridable.0.dart @@ -11,150 +11,73 @@ void main() { runApp( const MaterialApp( home: Scaffold( - body: Center(child: SimpleUSPhoneNumberEntry()), + body: Center(child: VerificationCodeGenerator()), ), ), ); } -// This implements a custom phone number input field that handles the -// [DeleteCharacterIntent] intent. -class DigitInput extends StatefulWidget { - const DigitInput({ - super.key, - required this.controller, - required this.focusNode, - this.maxLength, - this.textInputAction = TextInputAction.next, - }); +const CopyTextIntent copyTextIntent = CopyTextIntent._(); +class CopyTextIntent extends Intent { + const CopyTextIntent._(); +} - final int? maxLength; - final TextEditingController controller; - final TextInputAction textInputAction; - final FocusNode focusNode; +class CopyableText extends StatelessWidget { + const CopyableText({ super.key, required this.text }); - @override - DigitInputState createState() => DigitInputState(); -} + final String text; -class DigitInputState extends State { - late final Action _deleteTextAction = - CallbackAction( - onInvoke: (DeleteCharacterIntent intent) { - // For simplicity we delete everything in the section. - widget.controller.clear(); - return null; - }, - ); + void _copy(CopyTextIntent intent) => Clipboard.setData(ClipboardData(text: text)); @override Widget build(BuildContext context) { - return Actions( - actions: >{ - // Make the default `DeleteCharacterIntent` handler overridable. - DeleteCharacterIntent: Action.overridable( - defaultAction: _deleteTextAction, context: context), - }, - child: TextField( - controller: widget.controller, - textInputAction: TextInputAction.next, - keyboardType: TextInputType.phone, - focusNode: widget.focusNode, - decoration: const InputDecoration( - border: OutlineInputBorder(), + final Action defaultCopyAction = CallbackAction(onInvoke: _copy); + return Shortcuts( + shortcuts: const { SingleActivator(LogicalKeyboardKey.keyC, control: true) : copyTextIntent }, + child: Actions( + actions: > { + /// The Action is made overridable so the VerificationCodeGenerator + /// widget can override how copying is handled. + CopyTextIntent: Action.overridable(defaultAction: defaultCopyAction, context: context), + }, + child: Focus( + autofocus: true, + child: DefaultTextStyle.merge( + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + child: Text(text), + ), ), - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - LengthLimitingTextInputFormatter(widget.maxLength), - ], ), ); } } -class SimpleUSPhoneNumberEntry extends StatefulWidget { - const SimpleUSPhoneNumberEntry({super.key}); - - @override - State createState() => - _SimpleUSPhoneNumberEntryState(); -} - -class _DeleteDigit extends Action { - _DeleteDigit(this.state); +class VerificationCodeGenerator extends StatelessWidget { + const VerificationCodeGenerator({ super.key }); - final _SimpleUSPhoneNumberEntryState state; - @override - void invoke(DeleteCharacterIntent intent) { - assert(callingAction != null); - callingAction?.invoke(intent); - - if (state.lineNumberController.text.isEmpty && - state.lineNumberFocusNode.hasFocus) { - state.prefixFocusNode.requestFocus(); - } - - if (state.prefixController.text.isEmpty && state.prefixFocusNode.hasFocus) { - state.areaCodeFocusNode.requestFocus(); - } + void _copy(CopyTextIntent intent) { + debugPrint('Content copied'); + Clipboard.setData(const ClipboardData(text: '111222333')); } - // This action is only enabled when the `callingAction` exists and is - // enabled. - @override - bool get isActionEnabled => callingAction?.isActionEnabled ?? false; -} - -class _SimpleUSPhoneNumberEntryState extends State { - final FocusNode areaCodeFocusNode = FocusNode(); - final TextEditingController areaCodeController = TextEditingController(); - final FocusNode prefixFocusNode = FocusNode(); - final TextEditingController prefixController = TextEditingController(); - final FocusNode lineNumberFocusNode = FocusNode(); - final TextEditingController lineNumberController = TextEditingController(); - @override Widget build(BuildContext context) { return Actions( - actions: >{ - DeleteCharacterIntent: _DeleteDigit(this), - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + actions: > { CopyTextIntent: CallbackAction(onInvoke: _copy) }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, children: [ - const Expanded( - child: Text('(', textAlign: TextAlign.center), - ), - Expanded( - flex: 3, - child: DigitInput( - focusNode: areaCodeFocusNode, - controller: areaCodeController, - maxLength: 3, - ), - ), - const Expanded( - child: Text(')', textAlign: TextAlign.center), - ), - Expanded( - flex: 3, - child: DigitInput( - focusNode: prefixFocusNode, - controller: prefixController, - maxLength: 3, - ), - ), - const Expanded( - child: Text('-', textAlign: TextAlign.center), - ), - Expanded( - flex: 4, - child: DigitInput( - focusNode: lineNumberFocusNode, - controller: lineNumberController, - textInputAction: TextInputAction.done, - maxLength: 4, - ), + const Text('Press Ctrl-C to Copy'), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + CopyableText(text: '111'), + SizedBox(width: 5,), + CopyableText(text: '222'), + SizedBox(width: 5,), + CopyableText(text: '333'), + ], ), ], ), diff --git a/examples/api/lib/widgets/actions/actions.0.dart b/examples/api/lib/widgets/actions/actions.0.dart index 34636f326863a..080ec0332488e 100644 --- a/examples/api/lib/widgets/actions/actions.0.dart +++ b/examples/api/lib/widgets/actions/actions.0.dart @@ -155,7 +155,7 @@ class _MyStatefulWidgetState extends State { return Padding( padding: const EdgeInsets.all(8.0), child: Text('${model.data.value}', - style: Theme.of(context).textTheme.headline4), + style: Theme.of(context).textTheme.headlineMedium), ); }), IconButton( diff --git a/examples/api/lib/widgets/animated_list/animated_list.0.dart b/examples/api/lib/widgets/animated_list/animated_list.0.dart index 3869322a3c614..b6ca9ad40e663 100644 --- a/examples/api/lib/widgets/animated_list/animated_list.0.dart +++ b/examples/api/lib/widgets/animated_list/animated_list.0.dart @@ -186,7 +186,7 @@ class CardItem extends StatelessWidget { @override Widget build(BuildContext context) { - TextStyle textStyle = Theme.of(context).textTheme.headline4!; + TextStyle textStyle = Theme.of(context).textTheme.headlineMedium!; if (selected) { textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]); } diff --git a/examples/api/lib/widgets/animated_list/sliver_animated_list.0.dart b/examples/api/lib/widgets/animated_list/sliver_animated_list.0.dart index f29698aa87366..9ccf020dbc1ff 100644 --- a/examples/api/lib/widgets/animated_list/sliver_animated_list.0.dart +++ b/examples/api/lib/widgets/animated_list/sliver_animated_list.0.dart @@ -224,7 +224,7 @@ class CardItem extends StatelessWidget { child: Center( child: Text( 'Item $item', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ), ), diff --git a/examples/api/lib/widgets/animated_switcher/animated_switcher.0.dart b/examples/api/lib/widgets/animated_switcher/animated_switcher.0.dart index d0704f81a8dd4..7f563c88a1b28 100644 --- a/examples/api/lib/widgets/animated_switcher/animated_switcher.0.dart +++ b/examples/api/lib/widgets/animated_switcher/animated_switcher.0.dart @@ -50,7 +50,7 @@ class _MyStatefulWidgetState extends State { // child each time the count changes, so that it will begin its animation // when the count changes. key: ValueKey(_count), - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ), ElevatedButton( diff --git a/examples/api/lib/widgets/async/future_builder.0.dart b/examples/api/lib/widgets/async/future_builder.0.dart index f93ae2608b6fd..8c5c1d08ba87b 100644 --- a/examples/api/lib/widgets/async/future_builder.0.dart +++ b/examples/api/lib/widgets/async/future_builder.0.dart @@ -38,7 +38,7 @@ class _MyStatefulWidgetState extends State { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.headline2!, + style: Theme.of(context).textTheme.displayMedium!, textAlign: TextAlign.center, child: FutureBuilder( future: _calculation, // a previously-obtained Future or null diff --git a/examples/api/lib/widgets/async/stream_builder.0.dart b/examples/api/lib/widgets/async/stream_builder.0.dart index 4687ec834e6c6..6d1a63262e55f 100644 --- a/examples/api/lib/widgets/async/stream_builder.0.dart +++ b/examples/api/lib/widgets/async/stream_builder.0.dart @@ -48,7 +48,7 @@ class _MyStatefulWidgetState extends State { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.headline2!, + style: Theme.of(context).textTheme.displayMedium!, textAlign: TextAlign.center, child: Container( alignment: FractionalOffset.center, diff --git a/examples/api/lib/widgets/basic/listener.0.dart b/examples/api/lib/widgets/basic/listener.0.dart index 403918d9c0bce..2a3a76e4c9994 100644 --- a/examples/api/lib/widgets/basic/listener.0.dart +++ b/examples/api/lib/widgets/basic/listener.0.dart @@ -78,7 +78,7 @@ class _MyStatefulWidgetState extends State { 'You have pressed or released in this area this many times:'), Text( '$_downCounter presses\n$_upCounter releases', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), Text( 'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})', diff --git a/examples/api/lib/widgets/basic/mouse_region.0.dart b/examples/api/lib/widgets/basic/mouse_region.0.dart index f76d3fb7ee897..7fd154985fbfb 100644 --- a/examples/api/lib/widgets/basic/mouse_region.0.dart +++ b/examples/api/lib/widgets/basic/mouse_region.0.dart @@ -76,7 +76,7 @@ class _MyStatefulWidgetState extends State { 'You have entered or exited this box this many times:'), Text( '$_enterCounter Entries\n$_exitCounter Exits', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), Text( 'The cursor is here: (${x.toStringAsFixed(2)}, ${y.toStringAsFixed(2)})', diff --git a/examples/api/lib/widgets/focus_manager/focus_node.0.dart b/examples/api/lib/widgets/focus_manager/focus_node.0.dart index 257f089dd0955..699846cad97ab 100644 --- a/examples/api/lib/widgets/focus_manager/focus_node.0.dart +++ b/examples/api/lib/widgets/focus_manager/focus_node.0.dart @@ -121,7 +121,7 @@ class MyStatelessWidget extends StatelessWidget { Widget build(BuildContext context) { final TextTheme textTheme = Theme.of(context).textTheme; return DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: const ColorfulButton(), ); } diff --git a/examples/api/lib/widgets/focus_scope/focus.0.dart b/examples/api/lib/widgets/focus_scope/focus.0.dart index ef8689dcab97e..9ddba1ffec5fa 100644 --- a/examples/api/lib/widgets/focus_scope/focus.0.dart +++ b/examples/api/lib/widgets/focus_scope/focus.0.dart @@ -69,7 +69,7 @@ class _MyStatefulWidgetState extends State { debugLabel: 'Scope', autofocus: true, child: DefaultTextStyle( - style: textTheme.headline4!, + style: textTheme.headlineMedium!, child: Focus( onKey: _handleKeyPress, debugLabel: 'Button', diff --git a/examples/api/lib/widgets/focus_scope/focus_scope.0.dart b/examples/api/lib/widgets/focus_scope/focus_scope.0.dart index ffbc3825a8b92..48fe6dcc8d2f1 100644 --- a/examples/api/lib/widgets/focus_scope/focus_scope.0.dart +++ b/examples/api/lib/widgets/focus_scope/focus_scope.0.dart @@ -119,7 +119,7 @@ class _MyStatefulWidgetState extends State { child: const Text('ANOTHER BUTTON TO FOCUS'), ), DefaultTextStyle( - style: Theme.of(context).textTheme.headline2!, + style: Theme.of(context).textTheme.displayMedium!, child: const Text('BACKDROP')), ], ), @@ -148,7 +148,7 @@ class _MyStatefulWidgetState extends State { ? null : () => setState(() => backdropIsVisible = true), child: DefaultTextStyle( - style: Theme.of(context).textTheme.headline2!, + style: Theme.of(context).textTheme.displayMedium!, child: const Text('FOREGROUND')), ), ), diff --git a/examples/api/lib/widgets/navigator/navigator.0.dart b/examples/api/lib/widgets/navigator/navigator.0.dart index 6abd303d554f6..2baf740a32d68 100644 --- a/examples/api/lib/widgets/navigator/navigator.0.dart +++ b/examples/api/lib/widgets/navigator/navigator.0.dart @@ -31,7 +31,7 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.headline4!, + style: Theme.of(context).textTheme.headlineMedium!, child: Container( color: Colors.white, alignment: Alignment.center, @@ -47,7 +47,7 @@ class CollectPersonalInfoPage extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.headline4!, + style: Theme.of(context).textTheme.headlineMedium!, child: GestureDetector( onTap: () { // This moves from the personal info page to the credentials page, @@ -78,7 +78,7 @@ class ChooseCredentialsPage extends StatelessWidget { return GestureDetector( onTap: onSignupComplete, child: DefaultTextStyle( - style: Theme.of(context).textTheme.headline4!, + style: Theme.of(context).textTheme.headlineMedium!, child: Container( color: Colors.pinkAccent, alignment: Alignment.center, diff --git a/examples/api/lib/widgets/overlay/overlay.0.dart b/examples/api/lib/widgets/overlay/overlay.0.dart index c49ce87c8e18c..56d943b822b4c 100644 --- a/examples/api/lib/widgets/overlay/overlay.0.dart +++ b/examples/api/lib/widgets/overlay/overlay.0.dart @@ -132,7 +132,7 @@ class _OverlayExampleState extends State { ); // Add the OverlayEntry to the Overlay. - Overlay.of(context, debugRequiredFor: widget)!.insert(overlayEntry!); + Overlay.of(context, debugRequiredFor: widget).insert(overlayEntry!); } // Remove the OverlayEntry. diff --git a/examples/api/lib/widgets/restoration/restoration_mixin.0.dart b/examples/api/lib/widgets/restoration/restoration_mixin.0.dart index e7444b2476c9c..e857a8001a662 100644 --- a/examples/api/lib/widgets/restoration/restoration_mixin.0.dart +++ b/examples/api/lib/widgets/restoration/restoration_mixin.0.dart @@ -82,7 +82,7 @@ class _RestorableCounterState extends State ), Text( '${_counter.value}', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.0.dart b/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.0.dart index b51163c16a1e1..7331e5b1820f4 100644 --- a/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.0.dart +++ b/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.0.dart @@ -28,7 +28,7 @@ class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.bodyText2!, + style: Theme.of(context).textTheme.bodyMedium!, child: LayoutBuilder( builder: (BuildContext context, BoxConstraints viewportConstraints) { return SingleChildScrollView( diff --git a/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.1.dart b/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.1.dart index 07d94ad35cce4..feb42c3dd12b5 100644 --- a/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.1.dart +++ b/examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.1.dart @@ -28,7 +28,7 @@ class MyStatelessWidget extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultTextStyle( - style: Theme.of(context).textTheme.bodyText2!, + style: Theme.of(context).textTheme.bodyMedium!, child: LayoutBuilder( builder: (BuildContext context, BoxConstraints viewportConstraints) { return SingleChildScrollView( diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index d0292d87ba92e..bf6b12a41af19 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -30,10 +30,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,8 +43,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,17 +72,17 @@ dev_dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2b9d +# PUBSPEC CHECKSUM: 21a2 diff --git a/examples/api/test/material/card/card.1_test.dart b/examples/api/test/material/card/card.1_test.dart new file mode 100644 index 0000000000000..a107a42ef500c --- /dev/null +++ b/examples/api/test/material/card/card.1_test.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/card/card.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Card has clip applied', (WidgetTester tester) async { + await tester.pumpWidget(const example.MyApp()); + + final Card card = tester.firstWidget(find.byType(Card)); + expect(card.clipBehavior, Clip.hardEdge); + }); +} diff --git a/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart b/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart index 07cf30a649465..4e1d91388592b 100644 --- a/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart +++ b/examples/api/test/material/input_decorator/input_decoration.floating_label_style_error.0_test.dart @@ -7,7 +7,7 @@ import 'package:flutter_api_samples/material/input_decorator/input_decoration.fl import 'package:flutter_test/flutter_test.dart'; void main() { - testWidgets('InputDecorator label uses errorColor', (WidgetTester tester) async { + testWidgets('InputDecorator label uses error color', (WidgetTester tester) async { await tester.pumpWidget( const example.MyApp(), ); @@ -17,6 +17,6 @@ void main() { await tester.pumpAndSettle(); final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle))); - expect(label.style.color, theme.data.errorColor); + expect(label.style.color, theme.data.colorScheme.error); }); } diff --git a/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart b/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart index 05fd39fccd59e..95238b14125c4 100644 --- a/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart +++ b/examples/api/test/material/input_decorator/input_decoration.label_style_error.0_test.dart @@ -7,13 +7,13 @@ import 'package:flutter_api_samples/material/input_decorator/input_decoration.la import 'package:flutter_test/flutter_test.dart'; void main() { - testWidgets('InputDecorator label uses errorColor', (WidgetTester tester) async { + testWidgets('InputDecorator label uses error color', (WidgetTester tester) async { await tester.pumpWidget( const example.MyApp(), ); final Theme theme = tester.firstWidget(find.byType(Theme)); final AnimatedDefaultTextStyle label = tester.firstWidget(find.ancestor(of: find.text('Name'), matching: find.byType(AnimatedDefaultTextStyle))); - expect(label.style.color, theme.data.errorColor); + expect(label.style.color, theme.data.colorScheme.error); }); } diff --git a/examples/api/test/material/slider/slider.1_test.dart b/examples/api/test/material/slider/slider.1_test.dart new file mode 100644 index 0000000000000..df884ccbf2353 --- /dev/null +++ b/examples/api/test/material/slider/slider.1_test.dart @@ -0,0 +1,35 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/slider/slider.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Slider shows secondary track', (WidgetTester tester) async { + await tester.pumpWidget( + const example.MyApp(), + ); + + expect(find.byType(Slider), findsNWidgets(2)); + + final Finder slider1Finder = find.byType(Slider).at(0); + final Finder slider2Finder = find.byType(Slider).at(1); + + Slider slider1 = tester.widget(slider1Finder); + Slider slider2 = tester.widget(slider2Finder); + expect(slider1.secondaryTrackValue, slider2.value); + + const double targetValue = 0.8; + final Rect rect = tester.getRect(slider2Finder); + final Offset target = Offset(rect.left + (rect.right - rect.left) * targetValue, rect.top + (rect.bottom - rect.top) / 2); + await tester.tapAt(target); + await tester.pump(); + + slider1 = tester.widget(slider1Finder); + slider2 = tester.widget(slider2Finder); + expect(slider1.secondaryTrackValue, closeTo(targetValue, 0.05)); + expect(slider1.secondaryTrackValue, slider2.value); + }); +} diff --git a/examples/api/test/painting/border_side.stroke_align.0_test.dart b/examples/api/test/painting/border_side.stroke_align.0_test.dart new file mode 100644 index 0000000000000..dc322cd2ba584 --- /dev/null +++ b/examples/api/test/painting/border_side.stroke_align.0_test.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/painting/borders/border_side.stroke_align.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Finds the expected BorderedBox', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: example.StrokeAlignExample(), + ), + ); + + expect(find.byType(example.StrokeAlignExample), findsOneWidget); + expect(find.byType(example.BorderedBox), findsNWidgets(10)); + }); +} diff --git a/examples/api/test/widgets/actions/action.action_overridable.0_test.dart b/examples/api/test/widgets/actions/action.action_overridable.0_test.dart new file mode 100644 index 0000000000000..8558f547129bf --- /dev/null +++ b/examples/api/test/widgets/actions/action.action_overridable.0_test.dart @@ -0,0 +1,51 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_api_samples/widgets/actions/action.action_overridable.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final _MockClipboard mockClipboard = _MockClipboard(); + + testWidgets('Copies text on Ctrl-C', (WidgetTester tester) async { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); + await tester.pumpWidget(const MaterialApp( + home: Scaffold( + body: Center(child: example.VerificationCodeGenerator()), + ), + ), + ); + + expect(primaryFocus, isNotNull); + expect(mockClipboard.clipboardData, isNull); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.control); + await tester.sendKeyDownEvent(LogicalKeyboardKey.keyC); + await tester.sendKeyUpEvent(LogicalKeyboardKey.control); + await tester.sendKeyUpEvent(LogicalKeyboardKey.keyC); + + expect(mockClipboard.clipboardData?['text'], '111222333'); + }); +} + +class _MockClipboard { + _MockClipboard(); + + Map? clipboardData; + + Future handleMethodCall(MethodCall methodCall) async { + switch (methodCall.method) { + case 'Clipboard.setData': + clipboardData = methodCall.arguments as Map; + return null; + } + if (methodCall.method.startsWith('Clipboard')) { + throw StateError('unrecognized method call: ${methodCall.method}'); + } + return null; + } +} diff --git a/examples/api/test/widgets/heroes/hero.0_test.dart b/examples/api/test/widgets/heroes/hero.0_test.dart index 0cea769220650..058436ddb0936 100644 --- a/examples/api/test/widgets/heroes/hero.0_test.dart +++ b/examples/api/test/widgets/heroes/hero.0_test.dart @@ -13,32 +13,32 @@ void main() { ); expect(find.text('Hero Sample'), findsOneWidget); - await tester.tap(find.byType(example.BoxWidget)); + await tester.tap(find.byType(Container)); await tester.pump(); - Size heroSize = tester.getSize(find.byType(example.BoxWidget)); + Size heroSize = tester.getSize(find.byType(Container)); // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 103.0); expect(heroSize.height.roundToDouble(), 60.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 189.0); expect(heroSize.height.roundToDouble(), 146.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 199.0); expect(heroSize.height.roundToDouble(), 190.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize, const Size(200.0, 200.0)); expect(find.byIcon(Icons.arrow_back), findsOneWidget); @@ -47,25 +47,25 @@ void main() { // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 199.0); expect(heroSize.height.roundToDouble(), 190.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 189.0); expect(heroSize.height.roundToDouble(), 146.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize.width.roundToDouble(), 103.0); expect(heroSize.height.roundToDouble(), 60.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget)); + heroSize = tester.getSize(find.byType(Container)); expect(heroSize, const Size(50.0, 50.0)); }); } diff --git a/examples/api/test/widgets/heroes/hero.1_test.dart b/examples/api/test/widgets/heroes/hero.1_test.dart index 861e23bde7a46..18cd6011e7025 100644 --- a/examples/api/test/widgets/heroes/hero.1_test.dart +++ b/examples/api/test/widgets/heroes/hero.1_test.dart @@ -16,30 +16,30 @@ void main() { await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - Size heroSize = tester.getSize(find.byType(example.BoxWidget).first); + Size heroSize = tester.getSize(find.byType(Container).first); expect(heroSize, const Size(50.0, 50.0)); // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 171.0); expect(heroSize.height.roundToDouble(), 73.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 371.0); expect(heroSize.height.roundToDouble(), 273.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 398.0); expect(heroSize.height.roundToDouble(), 376.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize, const Size(400.0, 400.0)); expect(find.byIcon(Icons.arrow_back), findsOneWidget); @@ -48,25 +48,25 @@ void main() { // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 398.0); expect(heroSize.height.roundToDouble(), 376.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 371.0); expect(heroSize.height.roundToDouble(), 273.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 171.0); expect(heroSize.height.roundToDouble(), 73.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize, const Size(50.0, 50.0)); }); @@ -79,30 +79,30 @@ void main() { await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - Size heroSize = tester.getSize(find.byType(example.BoxWidget).last); + Size heroSize = tester.getSize(find.byType(Container).last); expect(heroSize, const Size(50.0, 50.0)); // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize.width.roundToDouble(), 133.0); expect(heroSize.height.roundToDouble(), 133.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize.width.roundToDouble(), 321.0); expect(heroSize.height.roundToDouble(), 321.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).first); + heroSize = tester.getSize(find.byType(Container).first); expect(heroSize.width.roundToDouble(), 398.0); expect(heroSize.height.roundToDouble(), 376.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize, const Size(400.0, 400.0)); expect(find.byIcon(Icons.arrow_back), findsOneWidget); @@ -111,25 +111,25 @@ void main() { // Jump 25% into the transition (total length = 300ms) await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize.width.roundToDouble(), 386.0); expect(heroSize.height.roundToDouble(), 386.0); // Jump to 50% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize.width.roundToDouble(), 321.0); expect(heroSize.height.roundToDouble(), 321.0); // Jump to 75% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize.width.roundToDouble(), 133.0); expect(heroSize.height.roundToDouble(), 133.0); // Jump to 100% into the transition. await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms - heroSize = tester.getSize(find.byType(example.BoxWidget).last); + heroSize = tester.getSize(find.byType(Container).last); expect(heroSize, const Size(50.0, 50.0)); }); } diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index fbe82f8e8d0ae..e35fec2b2c54c 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: dc60 +# PUBSPEC CHECKSUM: dd61 diff --git a/examples/flutter_view/windows/runner/flutter_window.cpp b/examples/flutter_view/windows/runner/flutter_window.cpp index 9cbd3109c3fee..f68aa9c26c0f5 100644 --- a/examples/flutter_view/windows/runner/flutter_window.cpp +++ b/examples/flutter_view/windows/runner/flutter_window.cpp @@ -30,6 +30,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/examples/flutter_view/windows/runner/main.cpp b/examples/flutter_view/windows/runner/main.cpp index 855a36a55ec85..6e195d383840c 100644 --- a/examples/flutter_view/windows/runner/main.cpp +++ b/examples/flutter_view/windows/runner/main.cpp @@ -31,7 +31,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"flutter_view", origin, size)) { + if (!window.Create(L"flutter_view", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/examples/flutter_view/windows/runner/win32_window.cpp b/examples/flutter_view/windows/runner/win32_window.cpp index 4021a2cfd40a1..635a5b29f532c 100644 --- a/examples/flutter_view/windows/runner/win32_window.cpp +++ b/examples/flutter_view/windows/runner/win32_window.cpp @@ -106,9 +106,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -121,7 +121,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -133,6 +133,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, diff --git a/examples/flutter_view/windows/runner/win32_window.h b/examples/flutter_view/windows/runner/win32_window.h index 1dab1777c4950..b161e9b84b8b3 100644 --- a/examples/flutter_view/windows/runner/win32_window.h +++ b/examples/flutter_view/windows/runner/win32_window.h @@ -32,15 +32,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index ca69a0ac4bb62..d22800e4a9f17 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -11,17 +11,17 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: sdk: flutter flutter_test: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,8 +31,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,14 +58,14 @@ dev_dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/examples/hello_world/windows/runner/flutter_window.cpp b/examples/hello_world/windows/runner/flutter_window.cpp index 9cbd3109c3fee..f68aa9c26c0f5 100644 --- a/examples/hello_world/windows/runner/flutter_window.cpp +++ b/examples/hello_world/windows/runner/flutter_window.cpp @@ -30,6 +30,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/examples/hello_world/windows/runner/main.cpp b/examples/hello_world/windows/runner/main.cpp index 38cfc87ad43b0..b99d1968aeefd 100644 --- a/examples/hello_world/windows/runner/main.cpp +++ b/examples/hello_world/windows/runner/main.cpp @@ -31,7 +31,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"hello_world", origin, size)) { + if (!window.Create(L"hello_world", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/examples/hello_world/windows/runner/win32_window.cpp b/examples/hello_world/windows/runner/win32_window.cpp index 20c47eacec2f7..9338467d48d55 100644 --- a/examples/hello_world/windows/runner/win32_window.cpp +++ b/examples/hello_world/windows/runner/win32_window.cpp @@ -106,9 +106,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -121,7 +121,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -133,6 +133,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, diff --git a/examples/hello_world/windows/runner/win32_window.h b/examples/hello_world/windows/runner/win32_window.h index 1dab1777c4950..b161e9b84b8b3 100644 --- a/examples/hello_world/windows/runner/win32_window.h +++ b/examples/hello_world/windows/runner/win32_window.h @@ -32,15 +32,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/examples/image_list/lib/main.dart b/examples/image_list/lib/main.dart index 6f5c76d9e713c..408f8f558cab7 100644 --- a/examples/image_list/lib/main.dart +++ b/examples/image_list/lib/main.dart @@ -210,7 +210,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index 039f53b29ce47..beb411d197f06 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -40,7 +40,7 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -53,4 +53,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: 2662 +# PUBSPEC CHECKSUM: 4c64 diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index c8785381ef303..042bf60915462 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -28,11 +28,11 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: assets: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 50ba +# PUBSPEC CHECKSUM: 76bc diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index cfa68a79cb482..57c8f9bd27dae 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -11,17 +11,17 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,8 +31,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,17 +58,17 @@ dev_dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/examples/platform_channel/windows/runner/flutter_window.cpp b/examples/platform_channel/windows/runner/flutter_window.cpp index 3dec3e82d70a5..1d252ecf80055 100644 --- a/examples/platform_channel/windows/runner/flutter_window.cpp +++ b/examples/platform_channel/windows/runner/flutter_window.cpp @@ -93,6 +93,11 @@ bool FlutterWindow::OnCreate() { })); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/examples/platform_channel/windows/runner/main.cpp b/examples/platform_channel/windows/runner/main.cpp index c52f49684e154..1cadf8d747d7a 100644 --- a/examples/platform_channel/windows/runner/main.cpp +++ b/examples/platform_channel/windows/runner/main.cpp @@ -30,7 +30,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"platform_channel", origin, size)) { + if (!window.Create(L"platform_channel", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/examples/platform_channel/windows/runner/win32_window.cpp b/examples/platform_channel/windows/runner/win32_window.cpp index 600749d7c10e0..87e7081db9480 100644 --- a/examples/platform_channel/windows/runner/win32_window.cpp +++ b/examples/platform_channel/windows/runner/win32_window.cpp @@ -102,8 +102,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -116,7 +117,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -128,6 +129,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, diff --git a/examples/platform_channel/windows/runner/win32_window.h b/examples/platform_channel/windows/runner/win32_window.h index 566ea77df3604..23ed729660307 100644 --- a/examples/platform_channel/windows/runner/win32_window.h +++ b/examples/platform_channel/windows/runner/win32_window.h @@ -32,14 +32,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 9250401b6d8b4..72d0d74375edb 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -11,17 +11,17 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,8 +31,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,17 +58,17 @@ dev_dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bbee +# PUBSPEC CHECKSUM: 59f3 diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index 500c403e1b264..4068cb4f08dbe 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -19,4 +19,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: dc60 +# PUBSPEC CHECKSUM: dd61 diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 30528e0240075..05628924b57d7 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -28,6 +28,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 50ba +# PUBSPEC CHECKSUM: 76bc diff --git a/packages/flutter/lib/fix_data.yaml b/packages/flutter/lib/fix_data.yaml index 9856e776b03d6..d77969bca88f2 100644 --- a/packages/flutter/lib/fix_data.yaml +++ b/packages/flutter/lib/fix_data.yaml @@ -17,6 +17,693 @@ version: 1 transforms: + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.background'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + field: 'backgroundColor' + inClass: 'ThemeData' + changes: + - kind: 'rename' + newName: 'colorScheme.background' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.background'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + method: 'copyWith' + inClass: 'ThemeData' + oneOf: + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme ==''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + backgroundColor: + kind: 'fragment' + value: 'arguments[backgroundColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.background'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + constructor: 'raw' + inClass: 'ThemeData' + oneOf: + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme ==''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + backgroundColor: + kind: 'fragment' + value: 'arguments[backgroundColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.background'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + constructor: '' + inClass: 'ThemeData' + oneOf: + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - if: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, background: {% backgroundColor %})' + requiredIf: "backgroundColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'backgroundColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + backgroundColor: + kind: 'fragment' + value: 'arguments[backgroundColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.error'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + field: 'errorColor' + inClass: 'ThemeData' + changes: + - kind: 'rename' + newName: 'colorScheme.error' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.error'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + method: 'copyWith' + inClass: 'ThemeData' + oneOf: + - if: "errorColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme ==''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + errorColor: + kind: 'fragment' + value: 'arguments[errorColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.error'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + constructor: 'raw' + inClass: 'ThemeData' + oneOf: + - if: "errorColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme ==''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + errorColor: + kind: 'fragment' + value: 'arguments[errorColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/110162 + - title: "Migrate to 'ColorScheme.error'" + date: 2022-08-24 + element: + uris: [ 'material.dart' ] + constructor: '' + inClass: 'ThemeData' + oneOf: + - if: "errorColor != '' && primarySwatch == '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme ==''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + changes: + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: 'ColorScheme.fromSwatch(primarySwatch: {% primarySwatch %}).copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme == ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + - if: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch == '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - if: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + changes: + - kind: 'removeParameter' + name: 'colorScheme' # Remove to add back with modification + - kind: 'addParameter' + index: 56 + name: 'colorScheme' + style: optional_named + argumentValue: + expression: '{% colorScheme %}.copyWith(primarySwatch: {% primarySwatch %}, error: {% errorColor %})' + requiredIf: "errorColor != '' && primarySwatch != '' && colorScheme != ''" + - kind: 'removeParameter' + name: 'errorColor' + - kind: 'removeParameter' + name: 'primarySwatch' + variables: + errorColor: + kind: 'fragment' + value: 'arguments[errorColor]' + primarySwatch: + kind: 'fragment' + value: 'arguments[primarySwatch]' + colorScheme: + kind: 'fragment' + value: 'arguments[colorScheme]' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'displayLarge'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline1 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'displayLarge' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'displayMedium'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline2 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'displayMedium' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'displaySmall'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline3 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'displaySmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'headlineMedium'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline4 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'headlineMedium' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'headlineSmall'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline5 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'headlineSmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'titleLarge'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: headline6 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'titleLarge' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'titleMedium'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: subtitle1 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'titleMedium' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'titleSmall'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: subtitle2 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'titleSmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'bodyLarge'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: bodyText1 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'bodyLarge' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'bodyMedium'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: bodyText2 + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'bodyMedium' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'bodySmall'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: caption + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'bodySmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'labelLarge'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: button + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'labelLarge' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: "Rename to 'labelSmall'" + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + getter: overline + inClass: 'TextTheme' + changes: + - kind: 'rename' + newName: 'labelSmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: 'Rename arguments' + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + constructor: '' + inClass: 'TextTheme' + changes: + - kind: 'renameParameter' + oldName: 'headline1' + newName: 'displayLarge' + - kind: 'renameParameter' + oldName: 'headline2' + newName: 'displayMedium' + - kind: 'renameParameter' + oldName: 'headline3' + newName: 'displaySmall' + - kind: 'renameParameter' + oldName: 'headline4' + newName: 'headlineMedium' + - kind: 'renameParameter' + oldName: 'headline5' + newName: 'headlineSmall' + - kind: 'renameParameter' + oldName: 'headline6' + newName: 'titleLarge' + - kind: 'renameParameter' + oldName: 'subtitle1' + newName: 'titleMedium' + - kind: 'renameParameter' + oldName: 'subtitle2' + newName: 'titleSmall' + - kind: 'renameParameter' + oldName: 'bodyText1' + newName: 'bodyLarge' + - kind: 'renameParameter' + oldName: 'bodyText2' + newName: 'bodyMedium' + - kind: 'renameParameter' + oldName: 'caption' + newName: 'bodySmall' + - kind: 'renameParameter' + oldName: 'button' + newName: 'labelLarge' + - kind: 'renameParameter' + oldName: 'overline' + newName: 'labelSmall' + + # Changes made in https://github.com/flutter/flutter/pull/109817 + - title: 'Rename arguments' + date: 2022-08-18 + element: + uris: [ 'material.dart' ] + method: 'copyWith' + inClass: 'TextTheme' + changes: + - kind: 'renameParameter' + oldName: 'headline1' + newName: 'displayLarge' + - kind: 'renameParameter' + oldName: 'headline2' + newName: 'displayMedium' + - kind: 'renameParameter' + oldName: 'headline3' + newName: 'displaySmall' + - kind: 'renameParameter' + oldName: 'headline4' + newName: 'headlineMedium' + - kind: 'renameParameter' + oldName: 'headline5' + newName: 'headlineSmall' + - kind: 'renameParameter' + oldName: 'headline6' + newName: 'titleLarge' + - kind: 'renameParameter' + oldName: 'subtitle1' + newName: 'titleMedium' + - kind: 'renameParameter' + oldName: 'subtitle2' + newName: 'titleSmall' + - kind: 'renameParameter' + oldName: 'bodyText1' + newName: 'bodyLarge' + - kind: 'renameParameter' + oldName: 'bodyText2' + newName: 'bodyMedium' + - kind: 'renameParameter' + oldName: 'caption' + newName: 'bodySmall' + - kind: 'renameParameter' + oldName: 'button' + newName: 'labelLarge' + - kind: 'renameParameter' + oldName: 'overline' + newName: 'labelSmall' + # Changes made in https://github.com/flutter/flutter/pull/109070 - title: "Remove 'selectedRowColor'" date: 2022-08-05 @@ -4810,4 +5497,4 @@ transforms: - kind: 'removeParameter' name: 'brightness' -# Before adding a new fix: read instructions at the top of this file. +# Before adding a new fix: read instructions at the top of this file. \ No newline at end of file diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 88edac4bb2d70..5e84a604a6e24 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -80,6 +80,8 @@ export 'src/material/expansion_panel.dart'; export 'src/material/expansion_tile.dart'; export 'src/material/expansion_tile_theme.dart'; export 'src/material/feedback.dart'; +export 'src/material/filled_button.dart'; +export 'src/material/filled_button_theme.dart'; export 'src/material/filter_chip.dart'; export 'src/material/flexible_space_bar.dart'; export 'src/material/floating_action_button.dart'; diff --git a/packages/flutter/lib/src/animation/animation_controller.dart b/packages/flutter/lib/src/animation/animation_controller.dart index da359a0780e23..25b5c04194466 100644 --- a/packages/flutter/lib/src/animation/animation_controller.dart +++ b/packages/flutter/lib/src/animation/animation_controller.dart @@ -757,6 +757,15 @@ class AnimationController extends Animation return result; } + /// Update the simulation without restarting the animation. + /// + /// The current simulation will be replaced with the provided [Simulation]. + /// It is only valid to call this when an animation is currently underway. + void updateSimulation(Simulation simulation) { + assert(isAnimating); + _simulation = simulation; + } + /// Stops running this animation. /// /// This does not trigger any notifications. The animation stops in its diff --git a/packages/flutter/lib/src/animation/curves.dart b/packages/flutter/lib/src/animation/curves.dart index b6eac1cac097e..08476c53f3649 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart @@ -508,7 +508,7 @@ abstract class Curve2D extends ParametricCurve { double end = 1.0, double tolerance = 1e-10, }) { - // The sampling algorithm is: + // The sampling algorithm is: // 1. Evaluate the area of the triangle (a proxy for the "flatness" of the // curve) formed by two points and a test point. // 2. If the area of the triangle is small enough (below tolerance), then @@ -675,7 +675,7 @@ class CatmullRomSpline extends Curve2D { /// interpolate. /// /// The internal curve data structures are lazily computed the first time - /// [transform] is called. If you would rather pre-compute the structures, + /// [transform] is called. If you would rather pre-compute the structures, /// use [CatmullRomSpline.precompute] instead. CatmullRomSpline( List controlPoints, { @@ -851,7 +851,7 @@ class CatmullRomCurve extends Curve { /// is equivalent to a linear interpolation between points. /// /// The internal curve data structures are lazily computed the first time - /// [transform] is called. If you would rather pre-compute the curve, use + /// [transform] is called. If you would rather pre-compute the curve, use /// [CatmullRomCurve.precompute] instead. /// /// All of the arguments must not be null. diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index 39216fc56aa1d..c50cb97c1178f 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -363,7 +363,7 @@ class _CupertinoContextMenuState extends State with Ticker ); }, ); - Overlay.of(context, rootOverlay: true, debugRequiredFor: widget)!.insert(_lastOverlayEntry!); + Overlay.of(context, rootOverlay: true, debugRequiredFor: widget).insert(_lastOverlayEntry!); _openController.forward(); } @@ -738,8 +738,8 @@ class _ContextMenuRoute extends PopupRoute { // buildTransitions as child, the idea being that buildTransitions will // animate the entire page into the scene. In the case of _ContextMenuRoute, // two individual pieces of the page are animated into the scene in - // buildTransitions, and a Container is returned here. - return Container(); + // buildTransitions, and a SizedBox.shrink() is returned here. + return const SizedBox.shrink(); } @override diff --git a/packages/flutter/lib/src/cupertino/desktop_text_selection.dart b/packages/flutter/lib/src/cupertino/desktop_text_selection.dart index 6c129c6f68565..9711d66f3aadc 100644 --- a/packages/flutter/lib/src/cupertino/desktop_text_selection.dart +++ b/packages/flutter/lib/src/cupertino/desktop_text_selection.dart @@ -153,7 +153,7 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin Widget build(BuildContext context) { // Don't render the menu until the state of the clipboard is known. if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } assert(debugCheckHasMediaQuery(context)); @@ -203,7 +203,7 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin // If there is no option available, build an empty widget. if (items.isEmpty) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } return _CupertinoDesktopTextSelectionToolbar( diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 435cf2b478c6b..1e4e6c05d798a 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -918,7 +918,7 @@ class _CupertinoDialogRenderElement extends RenderObjectElement { // // If all content and buttons do not fit on screen, and iOS is NOT in accessibility mode: // A minimum height for the action button section is calculated. The action -// button section will not be rendered shorter than this minimum. See +// button section will not be rendered shorter than this minimum. See // [_RenderCupertinoDialogActions] for the minimum height calculation. // // With the minimum action button section calculated, the content section can @@ -1335,7 +1335,7 @@ enum _AlertDialogSections { // The "content section" of a CupertinoAlertDialog. // -// If title is missing, then only content is added. If content is +// If title is missing, then only content is added. If content is // missing, then only title is added. If both are missing, then it returns // a SingleChildScrollView with a zero-sized Container. class _CupertinoAlertContentSection extends StatelessWidget { @@ -1389,7 +1389,7 @@ class _CupertinoAlertContentSection extends StatelessWidget { if (title == null && message == null) { return SingleChildScrollView( controller: scrollController, - child: const SizedBox(width: 0.0, height: 0.0), + child: const SizedBox.shrink(), ); } @@ -2254,7 +2254,7 @@ class _RenderCupertinoDialogActions extends RenderBox void _drawButtonBackgroundsAndDividersSingleRow(Canvas canvas, Offset offset) { // The vertical divider sits between the left button and right button (if - // the dialog has 2 buttons). The vertical divider is hidden if either the + // the dialog has 2 buttons). The vertical divider is hidden if either the // left or right button is pressed. final Rect verticalDivider = childCount == 2 && !_isButtonPressed ? Rect.fromLTWH( diff --git a/packages/flutter/lib/src/cupertino/icons.dart b/packages/flutter/lib/src/cupertino/icons.dart index fd02f2350fcf9..887d36c919a92 100644 --- a/packages/flutter/lib/src/cupertino/icons.dart +++ b/packages/flutter/lib/src/cupertino/icons.dart @@ -187,14 +187,14 @@ class CupertinoIcons { /// * [check_mark_circled], which is similar, but not filled in. static const IconData check_mark_circled_solid = IconData(0xf3ff, fontFamily: iconFont, fontPackage: iconFontPackage); - /// circle — Cupertino icon for an empty circle (a ring). An un-selected radio button. + /// circle — Cupertino icon for an empty circle (a ring). An un-selected radio button. /// /// See also: /// /// * [circle_filled], which is similar but filled in. static const IconData circle = IconData(0xf401, fontFamily: iconFont, fontPackage: iconFontPackage); - /// circle_fill — Cupertino icon for a filled circle. The circle is surrounded by a ring. A selected radio button. + /// circle_fill — Cupertino icon for a filled circle. The circle is surrounded by a ring. A selected radio button. /// This is the same icon as [circle_fill] in cupertino_icons 1.0.0+. /// /// See also: diff --git a/packages/flutter/lib/src/cupertino/picker.dart b/packages/flutter/lib/src/cupertino/picker.dart index 1476d162230a0..2c4aa5072cd1d 100644 --- a/packages/flutter/lib/src/cupertino/picker.dart +++ b/packages/flutter/lib/src/cupertino/picker.dart @@ -66,8 +66,8 @@ class CupertinoPicker extends StatefulWidget { /// the current picker index or for selecting an initial index value. /// /// The [looping] argument decides whether the child list loops and can be - /// scrolled infinitely. If set to true, scrolling past the end of the list - /// will loop the list back to the beginning. If set to false, the list will + /// scrolled infinitely. If set to true, scrolling past the end of the list + /// will loop the list back to the beginning. If set to false, the list will /// stop scrolling when you reach the end or the beginning. CupertinoPicker({ super.key, diff --git a/packages/flutter/lib/src/cupertino/refresh.dart b/packages/flutter/lib/src/cupertino/refresh.dart index dd2622e1dc979..351044a855d1b 100644 --- a/packages/flutter/lib/src/cupertino/refresh.dart +++ b/packages/flutter/lib/src/cupertino/refresh.dart @@ -422,7 +422,7 @@ class CupertinoSliverRefreshControl extends StatefulWidget { return CupertinoActivityIndicator(radius: radius * percentageComplete); case RefreshIndicatorMode.inactive: // Anything else doesn't show anything. - return Container(); + return const SizedBox.shrink(); } } diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index b758b177b66c7..7f204228d7c15 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -342,7 +342,7 @@ class CupertinoPageRoute extends PageRoute with CupertinoRouteTransitionMi super.settings, this.maintainState = true, super.fullscreenDialog, - super.preferRasterization = true, + super.allowSnapshotting = true, }) : assert(builder != null), assert(maintainState != null), assert(fullscreenDialog != null) { @@ -372,7 +372,7 @@ class CupertinoPageRoute extends PageRoute with CupertinoRouteTransitionMi class _PageBasedCupertinoPageRoute extends PageRoute with CupertinoRouteTransitionMixin { _PageBasedCupertinoPageRoute({ required CupertinoPage page, - super.preferRasterization = true, + super.allowSnapshotting = true, }) : assert(page != null), super(settings: page) { assert(opaque); @@ -419,7 +419,7 @@ class CupertinoPage extends Page { this.maintainState = true, this.title, this.fullscreenDialog = false, - this.preferRasterization = true, + this.allowSnapshotting = true, super.key, super.name, super.arguments, @@ -440,12 +440,12 @@ class CupertinoPage extends Page { /// {@macro flutter.widgets.PageRoute.fullscreenDialog} final bool fullscreenDialog; - /// {@macro flutter.widgets.TransitionRoute.preferRasterization} - final bool preferRasterization; + /// {@macro flutter.widgets.TransitionRoute.allowSnapshotting} + final bool allowSnapshotting; @override Route createRoute(BuildContext context) { - return _PageBasedCupertinoPageRoute(page: this, preferRasterization: preferRasterization); + return _PageBasedCupertinoPageRoute(page: this, allowSnapshotting: allowSnapshotting); } } @@ -920,10 +920,9 @@ class _CupertinoEdgeShadowDecoration extends Decoration { class _CupertinoEdgeShadowPainter extends BoxPainter { _CupertinoEdgeShadowPainter( this._decoration, - VoidCallback? onChange, + super.onChange, ) : assert(_decoration != null), - assert(_decoration._colors == null || _decoration._colors!.length > 1), - super(onChange); + assert(_decoration._colors == null || _decoration._colors!.length > 1); final _CupertinoEdgeShadowDecoration _decoration; diff --git a/packages/flutter/lib/src/cupertino/tab_scaffold.dart b/packages/flutter/lib/src/cupertino/tab_scaffold.dart index 3838a0410a9a1..b08f167ef3d5e 100644 --- a/packages/flutter/lib/src/cupertino/tab_scaffold.dart +++ b/packages/flutter/lib/src/cupertino/tab_scaffold.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/widgets.dart'; + import 'bottom_tab_bar.dart'; import 'colors.dart'; import 'theme.dart'; @@ -457,7 +458,7 @@ class _TabSwitchingViewState extends State<_TabSwitchingView> { _focusActiveTab(); } - // Will focus the active tab if the FocusScope above it has focus already. If + // Will focus the active tab if the FocusScope above it has focus already. If // not, then it will just mark it as the preferred focus for that scope. void _focusActiveTab() { if (tabFocusNodes.length != widget.tabCount) { @@ -504,7 +505,7 @@ class _TabSwitchingViewState extends State<_TabSwitchingView> { child: FocusScope( node: tabFocusNodes[index], child: Builder(builder: (BuildContext context) { - return shouldBuildTab[index] ? widget.tabBuilder(context, index) : Container(); + return shouldBuildTab[index] ? widget.tabBuilder(context, index) : const SizedBox.shrink(); }), ), ), diff --git a/packages/flutter/lib/src/cupertino/text_selection.dart b/packages/flutter/lib/src/cupertino/text_selection.dart index 3bebdac761814..67d004a50ed2a 100644 --- a/packages/flutter/lib/src/cupertino/text_selection.dart +++ b/packages/flutter/lib/src/cupertino/text_selection.dart @@ -82,7 +82,7 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe Widget build(BuildContext context) { // Don't render the menu until the state of the clipboard is known. if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } assert(debugCheckHasMediaQuery(context)); @@ -147,7 +147,7 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe // If there is no option available, build an empty widget. if (items.isEmpty) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } return CupertinoTextSelectionToolbar( @@ -266,7 +266,7 @@ class CupertinoTextSelectionControls extends TextSelectionControls { ); // iOS doesn't draw anything for collapsed selections. case TextSelectionHandleType.collapsed: - return const SizedBox(); + return const SizedBox.shrink(); } } diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart index 136be0505c1b2..85f117def94a1 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart @@ -187,8 +187,8 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { _RenderCupertinoTextSelectionToolbarShape( this._anchor, this._isAbove, - RenderBox? child, - ) : super(child); + super.child, + ); @override diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index ead94b297176a..5acfa98f0124c 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -6,6 +6,7 @@ import 'dart:convert' show json; import 'dart:developer' as developer; import 'dart:io' show exit; import 'dart:ui' as ui show Brightness, PlatformDispatcher, SingletonFlutterWindow, window; + // Before adding any more dart:ui imports, please read the README. import 'package:meta/meta.dart'; @@ -178,8 +179,8 @@ abstract class BindingBase { /// Each of these other bindings could individually access a /// [ui.SingletonFlutterWindow] statically, but that would preclude the /// ability to test its behaviors with a fake window for verification - /// purposes. Therefore, [BindingBase] exposes this - /// [ui.SingletonFlutterWindow] for use by other bindings. A subclass of + /// purposes. Therefore, [BindingBase] exposes this + /// [ui.SingletonFlutterWindow] for use by other bindings. A subclass of /// [BindingBase], such as [TestWidgetsFlutterBinding], can override this /// accessor to return a different [ui.SingletonFlutterWindow] implementation, /// such as a [TestWindow]. diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart index 2555a3d2247b4..65534fbc45e0f 100644 --- a/packages/flutter/lib/src/gestures/binding.dart +++ b/packages/flutter/lib/src/gestures/binding.dart @@ -360,7 +360,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H void _handlePointerEventImmediately(PointerEvent event) { HitTestResult? hitTestResult; if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent || event is PointerPanZoomStartEvent) { - assert(!_hitTests.containsKey(event.pointer)); + assert(!_hitTests.containsKey(event.pointer), 'Pointer of $event unexpectedly has a HitTestResult associated with it.'); hitTestResult = HitTestResult(); hitTest(hitTestResult, event.position); if (event is PointerDownEvent || event is PointerPanZoomStartEvent) { diff --git a/packages/flutter/lib/src/gestures/multidrag.dart b/packages/flutter/lib/src/gestures/multidrag.dart index b36d38453dcc5..2ad89dbc055f2 100644 --- a/packages/flutter/lib/src/gestures/multidrag.dart +++ b/packages/flutter/lib/src/gestures/multidrag.dart @@ -508,9 +508,8 @@ class VerticalMultiDragGestureRecognizer extends MultiDragGestureRecognizer { } class _DelayedPointerState extends MultiDragPointerState { - _DelayedPointerState(Offset initialPosition, Duration delay, PointerDeviceKind kind, DeviceGestureSettings? deviceGestureSettings) - : assert(delay != null), - super(initialPosition, kind, deviceGestureSettings) { + _DelayedPointerState(super.initialPosition, Duration delay, super.kind, super.deviceGestureSettings) + : assert(delay != null) { _timer = Timer(delay, _delayPassed); } diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 7247d61bba9ad..a8711a076b933 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -330,10 +330,10 @@ class AboutDialog extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 24.0), child: ListBody( children: [ - Text(name, style: Theme.of(context).textTheme.headline5), - Text(version, style: Theme.of(context).textTheme.bodyText2), + Text(name, style: Theme.of(context).textTheme.headlineSmall), + Text(version, style: Theme.of(context).textTheme.bodyMedium), const SizedBox(height: _textVerticalSeparation), - Text(applicationLegalese ?? '', style: Theme.of(context).textTheme.caption), + Text(applicationLegalese ?? '', style: Theme.of(context).textTheme.bodySmall), ], ), ), @@ -495,7 +495,7 @@ class _AboutProgram extends StatelessWidget { children: [ Text( name, - style: Theme.of(context).textTheme.headline5, + style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), if (icon != null) @@ -505,20 +505,20 @@ class _AboutProgram extends StatelessWidget { padding: const EdgeInsets.only(bottom: _textVerticalSeparation), child: Text( version, - style: Theme.of(context).textTheme.bodyText2, + style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ), if (legalese != null && legalese != '') Text( legalese!, - style: Theme.of(context).textTheme.caption, + style: Theme.of(context).textTheme.bodySmall, textAlign: TextAlign.center, ), const SizedBox(height: _textVerticalSeparation), Text( 'Powered by Flutter', - style: Theme.of(context).textTheme.bodyText2, + style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ], @@ -908,7 +908,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> { ); } return DefaultTextStyle( - style: theme.textTheme.caption!, + style: theme.textTheme.bodySmall!, child: page, ); } @@ -933,8 +933,8 @@ class _PackageLicensePageTitle extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: theme.headline6?.copyWith(color: color)), - Text(subtitle, style: theme.subtitle2?.copyWith(color: color)), + Text(title, style: theme.titleLarge?.copyWith(color: color)), + Text(subtitle, style: theme.titleSmall?.copyWith(color: color)), ], ); } @@ -1451,7 +1451,7 @@ class _DetailView extends StatelessWidget { @override Widget build(BuildContext context) { if (_arguments == null) { - return Container(); + return const SizedBox.shrink(); } final double screenHeight = MediaQuery.of(context).size.height; final double minHeight = (screenHeight - kToolbarHeight) / screenHeight; diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index b690185115366..2e740df38cba6 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -485,7 +485,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// The shape of the app bar's [Material] as well as its shadow. /// /// If this property is null, then [AppBarTheme.shape] of - /// [ThemeData.appBarTheme] is used. Both properties default to null. + /// [ThemeData.appBarTheme] is used. Both properties default to null. /// If both properties are null then the shape of the app bar's [Material] /// is just a simple rectangle. /// @@ -561,7 +561,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// /// The AppBar is built within a `AnnotatedRegion` /// which causes [SystemChrome.setSystemUIOverlayStyle] to be called - /// automatically. Apps should not enclose the AppBar with + /// automatically. Apps should not enclose the AppBar with /// their own [AnnotatedRegion]. /// {@endtemplate} /// @@ -739,7 +739,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// /// If this property is null, then [AppBarTheme.toolbarTextStyle] of /// [ThemeData.appBarTheme] is used. If that is also null, the default - /// value is a copy of the overall theme's [TextTheme.bodyText2] + /// value is a copy of the overall theme's [TextTheme.bodyMedium] /// [TextStyle], with color set to the app bar's [foregroundColor]. /// {@endtemplate} /// @@ -755,7 +755,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// /// If this property is null, then [AppBarTheme.titleTextStyle] of /// [ThemeData.appBarTheme] is used. If that is also null, the default - /// value is a copy of the overall theme's [TextTheme.headline6] + /// value is a copy of the overall theme's [TextTheme.titleLarge] /// [TextStyle], with color set to the app bar's [foregroundColor]. /// {@endtemplate} /// @@ -780,7 +780,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// The AppBar's descendants are built within a /// `AnnotatedRegion` widget, which causes /// [SystemChrome.setSystemUIOverlayStyle] to be called - /// automatically. Apps should not enclose an AppBar with their + /// automatically. Apps should not enclose an AppBar with their /// own [AnnotatedRegion]. /// {@endtemplate} // @@ -942,25 +942,27 @@ class _AppBarState extends State { ?? appBarTheme.iconTheme ?? defaults.iconTheme!.copyWith(color: foregroundColor); + final Color? actionForegroundColor = widget.foregroundColor + ?? appBarTheme.foregroundColor; IconThemeData actionsIconTheme = widget.actionsIconTheme ?? appBarTheme.actionsIconTheme ?? widget.iconTheme ?? appBarTheme.iconTheme - ?? defaults.actionsIconTheme?.copyWith(color: foregroundColor) + ?? defaults.actionsIconTheme?.copyWith(color: actionForegroundColor) ?? overallIconTheme; TextStyle? toolbarTextStyle = backwardsCompatibility - ? widget.textTheme?.bodyText2 - ?? appBarTheme.textTheme?.bodyText2 - ?? theme.primaryTextTheme.bodyText2 + ? widget.textTheme?.bodyMedium + ?? appBarTheme.textTheme?.bodyMedium + ?? theme.primaryTextTheme.bodyMedium : widget.toolbarTextStyle ?? appBarTheme.toolbarTextStyle ?? defaults.toolbarTextStyle?.copyWith(color: foregroundColor); TextStyle? titleTextStyle = backwardsCompatibility - ? widget.textTheme?.headline6 - ?? appBarTheme.textTheme?.headline6 - ?? theme.primaryTextTheme.headline6 + ? widget.textTheme?.titleLarge + ?? appBarTheme.textTheme?.titleLarge + ?? theme.primaryTextTheme.titleLarge : widget.titleTextStyle ?? appBarTheme.titleTextStyle ?? defaults.titleTextStyle?.copyWith(color: foregroundColor); @@ -998,11 +1000,20 @@ class _AppBarState extends State { } } if (leading != null) { - leading = Container( - alignment: Alignment.center, - constraints: BoxConstraints.tightFor(width: widget.leadingWidth ?? _kLeadingWidth), - child: leading, - ); + // Based on the Material Design 3 specs, the leading IconButton should have + // a size of 48x48, and a highlight size of 40x40. Users can also put other + // type of widgets on leading with the original config. + if (theme.useMaterial3) { + leading = ConstrainedBox( + constraints: BoxConstraints.tightFor(width: widget.leadingWidth ?? _kLeadingWidth), + child: leading is IconButton ? Center(child: leading) : leading, + ); + } else { + leading = ConstrainedBox( + constraints: BoxConstraints.tightFor(width: widget.leadingWidth ?? _kLeadingWidth), + child: leading, + ); + } } Widget? title = widget.title; @@ -2324,10 +2335,10 @@ class _AppBarDefaultsM2 extends AppBarTheme { IconThemeData? get iconTheme => _theme.iconTheme; @override - TextStyle? get toolbarTextStyle => _theme.textTheme.bodyText2; + TextStyle? get toolbarTextStyle => _theme.textTheme.bodyMedium; @override - TextStyle? get titleTextStyle => _theme.textTheme.headline6; + TextStyle? get titleTextStyle => _theme.textTheme.titleLarge; } // BEGIN GENERATED TOKEN PROPERTIES - AppBar @@ -2375,7 +2386,7 @@ class _AppBarDefaultsM3 extends AppBarTheme { ); @override - TextStyle? get toolbarTextStyle => _textTheme.bodyText2; + TextStyle? get toolbarTextStyle => _textTheme.bodyMedium; @override TextStyle? get titleTextStyle => _textTheme.titleLarge; diff --git a/packages/flutter/lib/src/material/back_button.dart b/packages/flutter/lib/src/material/back_button.dart index 4d1f1c874cc71..3feaba527d756 100644 --- a/packages/flutter/lib/src/material/back_button.dart +++ b/packages/flutter/lib/src/material/back_button.dart @@ -27,22 +27,31 @@ class BackButtonIcon extends StatelessWidget { /// the current platform (as obtained from the [Theme]). const BackButtonIcon({ super.key }); - /// Returns the appropriate "back" icon for the given `platform`. - static IconData _getIconData(TargetPlatform platform) { - switch (platform) { + @override + Widget build(BuildContext context) { + final String? semanticsLabel; + final IconData data; + switch (Theme.of(context).platform) { case TargetPlatform.android: + // Android uses semantics label to annotate the back button. + semanticsLabel = MaterialLocalizations.of(context).backButtonTooltip; + data = Icons.arrow_back; + break; case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - return Icons.arrow_back; + semanticsLabel = null; + data = Icons.arrow_back; + break; case TargetPlatform.iOS: case TargetPlatform.macOS: - return Icons.arrow_back_ios; + data = Icons.arrow_back_ios; + semanticsLabel = null; + break; } - } - @override - Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context).platform)); + return Icon(data, semanticLabel: semanticsLabel); + } } /// A Material Design back button. @@ -149,8 +158,22 @@ class CloseButton extends StatelessWidget { @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); + final String? semanticsLabel; + switch (Theme.of(context).platform) { + case TargetPlatform.android: + // Android uses semantics label to annotate the close button. + semanticsLabel = MaterialLocalizations.of(context).closeButtonTooltip; + break; + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + case TargetPlatform.iOS: + case TargetPlatform.macOS: + semanticsLabel = null; + break; + } return IconButton( - icon: const Icon(Icons.close), + icon: Icon(Icons.close, semanticLabel: semanticsLabel), color: color, tooltip: MaterialLocalizations.of(context).closeButtonTooltip, onPressed: () { diff --git a/packages/flutter/lib/src/material/banner.dart b/packages/flutter/lib/src/material/banner.dart index 15da6e828c78f..83849d048901d 100644 --- a/packages/flutter/lib/src/material/banner.dart +++ b/packages/flutter/lib/src/material/banner.dart @@ -102,12 +102,15 @@ class MaterialBanner extends StatefulWidget { this.elevation, this.leading, this.backgroundColor, + this.surfaceTintColor, + this.shadowColor, + this.dividerColor, this.padding, this.leadingPadding, this.forceActionsBelow = false, this.overflowAlignment = OverflowBarAlignment.end, this.animation, - this.onVisible + this.onVisible, }) : assert(elevation == null || elevation >= 0.0), assert(content != null), assert(actions != null), @@ -121,7 +124,7 @@ class MaterialBanner extends StatefulWidget { /// Style for the text in the [content] of the [MaterialBanner]. /// /// If `null`, [MaterialBannerThemeData.contentTextStyle] is used. If that is - /// also `null`, [TextTheme.bodyText2] of [ThemeData.textTheme] is used. + /// also `null`, [TextTheme.bodyMedium] of [ThemeData.textTheme] is used. final TextStyle? contentTextStyle; /// The set of actions that are displayed at the bottom or trailing side of @@ -153,6 +156,29 @@ class MaterialBanner extends StatefulWidget { /// also `null`, [ColorScheme.surface] of [ThemeData.colorScheme] is used. final Color? backgroundColor; + /// The color used as an overlay on [backgroundColor] to indicate elevation. + /// + /// If null, [MaterialBannerThemeData.surfaceTintColor] is used. If that + /// is also null, the default value is [ColorScheme.surfaceTint]. + /// + /// See [Material.surfaceTintColor] for more details on how this + /// overlay is applied. + final Color? surfaceTintColor; + + /// The color of the shadow below the [MaterialBanner]. + /// + /// If this property is null, then [MaterialBannerThemeData.shadowColor] of + /// [ThemeData.bannerTheme] is used. If that is also null, the default value + /// is null. + final Color? shadowColor; + + /// The color of the divider. + /// + /// If this property is null, then [MaterialBannerThemeData.dividerColor] of + /// [ThemeData.bannerTheme] is used. If that is also null, the default value + /// is [ColorScheme.surfaceVariant]. + final Color? dividerColor; + /// The amount of space by which to inset the [content]. /// /// If the [actions] are below the [content], this defaults to @@ -273,6 +299,7 @@ class _MaterialBannerState extends State { final ThemeData theme = Theme.of(context); final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context); + final MaterialBannerThemeData defaults = theme.useMaterial3 ? _BannerDefaultsM3(context) : _BannerDefaultsM2(context); final bool isSingleRow = widget.actions.length == 1 && !widget.forceActionsBelow; final EdgeInsetsGeometry padding = widget.padding ?? bannerTheme.padding ?? (isSingleRow @@ -296,16 +323,26 @@ class _MaterialBannerState extends State { final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0; final Color backgroundColor = widget.backgroundColor ?? bannerTheme.backgroundColor - ?? theme.colorScheme.surface; + ?? defaults.backgroundColor!; + final Color? surfaceTintColor = widget.surfaceTintColor + ?? bannerTheme.surfaceTintColor + ?? defaults.surfaceTintColor; + final Color? shadowColor = widget.shadowColor + ?? bannerTheme.shadowColor; + final Color? dividerColor = widget.dividerColor + ?? bannerTheme.dividerColor + ?? defaults.dividerColor; final TextStyle? textStyle = widget.contentTextStyle ?? bannerTheme.contentTextStyle - ?? theme.textTheme.bodyText2; + ?? defaults.contentTextStyle; Widget materialBanner = Container( margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0), child: Material( elevation: elevation, color: backgroundColor, + surfaceTintColor: surfaceTintColor, + shadowColor: shadowColor, child: Column( mainAxisSize: MainAxisSize.min, children: [ @@ -331,9 +368,8 @@ class _MaterialBannerState extends State { ), if (!isSingleRow) buttonBar, - if (elevation == 0) - const Divider(height: 0), + Divider(height: 0, color: dividerColor), ], ), ), @@ -394,3 +430,51 @@ class _MaterialBannerState extends State { ); } } + +class _BannerDefaultsM2 extends MaterialBannerThemeData { + _BannerDefaultsM2(this.context) + : _theme = Theme.of(context), + super(elevation: 0.0); + + final BuildContext context; + final ThemeData _theme; + + @override + Color? get backgroundColor => _theme.colorScheme.surface; + + @override + Color? get dividerColor => Theme.of(context).colorScheme.surfaceVariant; + + @override + TextStyle? get contentTextStyle => _theme.textTheme.bodyText2; +} + +// BEGIN GENERATED TOKEN PROPERTIES - Banner + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Token database version: v0_101 + +class _BannerDefaultsM3 extends MaterialBannerThemeData { + const _BannerDefaultsM3(this.context) + : super(elevation: 1.0); + + final BuildContext context; + + @override + Color? get backgroundColor => Theme.of(context).colorScheme.surface; + + @override + Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; + + @override + Color? get dividerColor => Theme.of(context).colorScheme.surfaceVariant; + + @override + TextStyle? get contentTextStyle => Theme.of(context).textTheme.bodyMedium; +} + +// END GENERATED TOKEN PROPERTIES - Banner diff --git a/packages/flutter/lib/src/material/banner_theme.dart b/packages/flutter/lib/src/material/banner_theme.dart index 5081f8825e783..8b0b183c6cd7f 100644 --- a/packages/flutter/lib/src/material/banner_theme.dart +++ b/packages/flutter/lib/src/material/banner_theme.dart @@ -35,6 +35,9 @@ class MaterialBannerThemeData with Diagnosticable { /// [ThemeData.bannerTheme]. const MaterialBannerThemeData({ this.backgroundColor, + this.surfaceTintColor, + this.shadowColor, + this.dividerColor, this.contentTextStyle, this.elevation, this.padding, @@ -44,6 +47,15 @@ class MaterialBannerThemeData with Diagnosticable { /// The background color of a [MaterialBanner]. final Color? backgroundColor; + /// Overrides the default value of [MaterialBanner.surfaceTintColor]. + final Color? surfaceTintColor; + + /// Overrides the default value of [MaterialBanner.shadowColor]. + final Color? shadowColor; + + /// Overrides the default value of [MaterialBanner.dividerColor]. + final Color? dividerColor; + /// Used to configure the [DefaultTextStyle] for the [MaterialBanner.content] /// widget. final TextStyle? contentTextStyle; @@ -63,6 +75,9 @@ class MaterialBannerThemeData with Diagnosticable { /// new values. MaterialBannerThemeData copyWith({ Color? backgroundColor, + Color? surfaceTintColor, + Color? shadowColor, + Color? dividerColor, TextStyle? contentTextStyle, double? elevation, EdgeInsetsGeometry? padding, @@ -70,6 +85,9 @@ class MaterialBannerThemeData with Diagnosticable { }) { return MaterialBannerThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, + shadowColor: shadowColor ?? this.shadowColor, + dividerColor: dividerColor ?? this.dividerColor, contentTextStyle: contentTextStyle ?? this.contentTextStyle, elevation: elevation ?? this.elevation, padding: padding ?? this.padding, @@ -86,6 +104,9 @@ class MaterialBannerThemeData with Diagnosticable { assert(t != null); return MaterialBannerThemeData( backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), + surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), + shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), + dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t), contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), @@ -96,6 +117,9 @@ class MaterialBannerThemeData with Diagnosticable { @override int get hashCode => Object.hash( backgroundColor, + surfaceTintColor, + shadowColor, + dividerColor, contentTextStyle, elevation, padding, @@ -111,19 +135,25 @@ class MaterialBannerThemeData with Diagnosticable { return false; } return other is MaterialBannerThemeData - && other.backgroundColor == backgroundColor - && other.contentTextStyle == contentTextStyle - && other.elevation == elevation - && other.padding == padding - && other.leadingPadding == leadingPadding; + && other.backgroundColor == backgroundColor + && other.surfaceTintColor == surfaceTintColor + && other.shadowColor == shadowColor + && other.dividerColor == dividerColor + && other.contentTextStyle == contentTextStyle + && other.elevation == elevation + && other.padding == padding + && other.leadingPadding == leadingPadding; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); + properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); + properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); + properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null)); properties.add(DiagnosticsProperty('contentTextStyle', contentTextStyle, defaultValue: null)); - properties.add(DiagnosticsProperty('elevation', elevation, defaultValue: null)); + properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty('leadingPadding', leadingPadding, defaultValue: null)); } diff --git a/packages/flutter/lib/src/material/button.dart b/packages/flutter/lib/src/material/button.dart index 9ee96c048d179..5c9a4aeb54680 100644 --- a/packages/flutter/lib/src/material/button.dart +++ b/packages/flutter/lib/src/material/button.dart @@ -26,14 +26,16 @@ import 'theme_data.dart'; /// from the themes or from app-specific sources. /// /// This class is planned to be deprecated in a future release, see -/// [ButtonStyleButton], the base class of [TextButton], [ElevatedButton], and -/// [OutlinedButton]. +/// [ButtonStyleButton], the base class of [ElevatedButton], [FilledButton], +/// [OutlinedButton] and [TextButton]. /// /// See also: /// -/// * [TextButton], a simple flat button without a shadow. /// * [ElevatedButton], a filled button whose material elevates when pressed. -/// * [OutlinedButton], a [TextButton] with a border outline. +/// * [FilledButton], a filled button that doesn't elevate when pressed. +/// * [FilledButton.tonal], a filled button variant that uses a secondary fill color. +/// * [OutlinedButton], a button with an outlined border and no fill color. +/// * [TextButton], a button with no outline or fill color. @Category(['Material', 'Button']) class RawMaterialButton extends StatefulWidget { /// Create a button based on [Semantics], [Material], and [InkWell] widgets. diff --git a/packages/flutter/lib/src/material/button_style.dart b/packages/flutter/lib/src/material/button_style.dart index 6e90614be59e2..3eec3280ae9ac 100644 --- a/packages/flutter/lib/src/material/button_style.dart +++ b/packages/flutter/lib/src/material/button_style.dart @@ -74,12 +74,12 @@ import 'theme_data.dart'; /// Configuring a ButtonStyle directly makes it possible to very /// precisely control the button’s visual attributes for all states. /// This level of control is typically required when a custom -/// “branded” look and feel is desirable. However, in many cases it’s +/// “branded” look and feel is desirable. However, in many cases it’s /// useful to make relatively sweeping changes based on a few initial /// parameters with simple values. The button styleFrom() methods /// enable such sweeping changes. See for example: -/// [TextButton.styleFrom], [ElevatedButton.styleFrom], -/// [OutlinedButton.styleFrom]. +/// [ElevatedButton.styleFrom], [FilledButton.styleFrom], +/// [OutlinedButton.styleFrom], [TextButton.styleFrom]. /// /// For example, to override the default text and icon colors for a /// [TextButton], as well as its overlay color, with all of the @@ -119,8 +119,8 @@ import 'theme_data.dart'; /// | Type | Flutter implementation | /// | :----------- | :---------------------- | /// | Elevated | [ElevatedButton] | -/// | Filled | Styled [ElevatedButton] | -/// | Filled Tonal | Styled [ElevatedButton] | +/// | Filled | [FilledButton] | +/// | Filled Tonal | [FilledButton.tonal] | /// | Outlined | [OutlinedButton] | /// | Text | [TextButton] | /// @@ -132,9 +132,10 @@ import 'theme_data.dart'; /// /// See also: /// -/// * [TextButtonTheme], the theme for [TextButton]s. /// * [ElevatedButtonTheme], the theme for [ElevatedButton]s. +/// * [FilledButtonTheme], the theme for [FilledButton]s. /// * [OutlinedButtonTheme], the theme for [OutlinedButton]s. +/// * [TextButtonTheme], the theme for [TextButton]s. @immutable class ButtonStyle with Diagnosticable { /// Create a [ButtonStyle]. @@ -484,18 +485,18 @@ class ButtonStyle with Diagnosticable { return null; } return ButtonStyle( - textStyle: _lerpProperties(a?.textStyle, b?.textStyle, t, TextStyle.lerp), - backgroundColor: _lerpProperties(a?.backgroundColor, b?.backgroundColor, t, Color.lerp), - foregroundColor: _lerpProperties(a?.foregroundColor, b?.foregroundColor, t, Color.lerp), - overlayColor: _lerpProperties(a?.overlayColor, b?.overlayColor, t, Color.lerp), - shadowColor: _lerpProperties(a?.shadowColor, b?.shadowColor, t, Color.lerp), - surfaceTintColor: _lerpProperties(a?.surfaceTintColor, b?.surfaceTintColor, t, Color.lerp), - elevation: _lerpProperties(a?.elevation, b?.elevation, t, lerpDouble), - padding: _lerpProperties(a?.padding, b?.padding, t, EdgeInsetsGeometry.lerp), - minimumSize: _lerpProperties(a?.minimumSize, b?.minimumSize, t, Size.lerp), - fixedSize: _lerpProperties(a?.fixedSize, b?.fixedSize, t, Size.lerp), - maximumSize: _lerpProperties(a?.maximumSize, b?.maximumSize, t, Size.lerp), - iconSize: _lerpProperties(a?.iconSize, b?.iconSize, t, lerpDouble), + textStyle: MaterialStateProperty.lerp(a?.textStyle, b?.textStyle, t, TextStyle.lerp), + backgroundColor: MaterialStateProperty.lerp(a?.backgroundColor, b?.backgroundColor, t, Color.lerp), + foregroundColor: MaterialStateProperty.lerp(a?.foregroundColor, b?.foregroundColor, t, Color.lerp), + overlayColor: MaterialStateProperty.lerp(a?.overlayColor, b?.overlayColor, t, Color.lerp), + shadowColor: MaterialStateProperty.lerp(a?.shadowColor, b?.shadowColor, t, Color.lerp), + surfaceTintColor: MaterialStateProperty.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t, Color.lerp), + elevation: MaterialStateProperty.lerp(a?.elevation, b?.elevation, t, lerpDouble), + padding: MaterialStateProperty.lerp(a?.padding, b?.padding, t, EdgeInsetsGeometry.lerp), + minimumSize: MaterialStateProperty.lerp(a?.minimumSize, b?.minimumSize, t, Size.lerp), + fixedSize: MaterialStateProperty.lerp(a?.fixedSize, b?.fixedSize, t, Size.lerp), + maximumSize: MaterialStateProperty.lerp(a?.maximumSize, b?.maximumSize, t, Size.lerp), + iconSize: MaterialStateProperty.lerp(a?.iconSize, b?.iconSize, t, lerpDouble), side: _lerpSides(a?.side, b?.side, t), shape: MaterialStateProperty.lerp(a?.shape, b?.shape, t, OutlinedBorder.lerp), mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, @@ -508,14 +509,6 @@ class ButtonStyle with Diagnosticable { ); } - static MaterialStateProperty? _lerpProperties(MaterialStateProperty? a, MaterialStateProperty? b, double t, T? Function(T?, T?, double) lerpFunction ) { - // Avoid creating a _LerpProperties object for a common case. - if (a == null && b == null) { - return null; - } - return _LerpProperties(a, b, t, lerpFunction); - } - // Special case because BorderSide.lerp() doesn't support null arguments static MaterialStateProperty? _lerpSides(MaterialStateProperty? a, MaterialStateProperty? b, double t) { if (a == null && b == null) { @@ -525,22 +518,6 @@ class ButtonStyle with Diagnosticable { } } -class _LerpProperties implements MaterialStateProperty { - const _LerpProperties(this.a, this.b, this.t, this.lerpFunction); - - final MaterialStateProperty? a; - final MaterialStateProperty? b; - final double t; - final T? Function(T?, T?, double) lerpFunction; - - @override - T? resolve(Set states) { - final T? resolvedA = a?.resolve(states); - final T? resolvedB = b?.resolve(states); - return lerpFunction(resolvedA, resolvedB, t); - } -} - class _LerpSides implements MaterialStateProperty { const _LerpSides(this.a, this.b, this.t); diff --git a/packages/flutter/lib/src/material/button_style_button.dart b/packages/flutter/lib/src/material/button_style_button.dart index 3dd671beb3887..8bfb967d84adf 100644 --- a/packages/flutter/lib/src/material/button_style_button.dart +++ b/packages/flutter/lib/src/material/button_style_button.dart @@ -21,10 +21,13 @@ import 'theme_data.dart'; /// Concrete subclasses must override [defaultStyleOf] and [themeStyleOf]. /// /// See also: -/// -/// * [TextButton], a simple ButtonStyleButton without a shadow. -/// * [ElevatedButton], a filled ButtonStyleButton whose material elevates when pressed. -/// * [OutlinedButton], similar to [TextButton], but with an outline. +/// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [FilledButton], a filled button that doesn't elevate when pressed. +/// * [FilledButton.tonal], a filled button variant that uses a secondary fill color. +/// * [OutlinedButton], a button with an outlined border and no fill color. +/// * [TextButton], a button with no outline or fill color. +/// * , an overview of each of +/// the Material Design button types and how they should be used in designs. abstract class ButtonStyleButton extends StatefulWidget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -191,9 +194,10 @@ abstract class ButtonStyleButton extends StatefulWidget { /// See also: /// /// * [ButtonStyleButton], the [StatefulWidget] subclass for which this class is the [State]. -/// * [TextButton], a simple button without a shadow. /// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [FilledButton], a filled ButtonStyleButton that doesn't elevate when pressed. /// * [OutlinedButton], similar to [TextButton], but with an outline. +/// * [TextButton], a simple button without a shadow. class _ButtonStyleState extends State with TickerProviderStateMixin { AnimationController? controller; double? elevation; diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart index 0f734abbd5f8e..4981926f409ad 100644 --- a/packages/flutter/lib/src/material/button_theme.dart +++ b/packages/flutter/lib/src/material/button_theme.dart @@ -48,9 +48,10 @@ enum ButtonBarLayoutBehavior { /// This class is planned to be deprecated in a future release. /// Please use one or more of these buttons and associated themes instead: /// -/// * [TextButton], [TextButtonTheme], [TextButtonThemeData], /// * [ElevatedButton], [ElevatedButtonTheme], [ElevatedButtonThemeData], +/// * [FilledButton], [FilledButtonTheme], [FilledButtonThemeData], /// * [OutlinedButton], [OutlinedButtonTheme], [OutlinedButtonThemeData] +/// * [TextButton], [TextButtonTheme], [TextButtonThemeData], /// /// A button theme can be specified as part of the overall Material theme /// using [ThemeData.buttonTheme]. The Material theme's button theme data diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 7a146930ee7f7..9b24edd7fe9ef 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -394,7 +394,7 @@ class _DatePickerModeToggleButtonState extends State<_DatePickerModeToggleButton child: Text( widget.title, overflow: TextOverflow.ellipsis, - style: textTheme.subtitle2?.copyWith( + style: textTheme.titleSmall?.copyWith( color: controlColor, ), ), @@ -937,10 +937,10 @@ class _DayPickerState extends State<_DayPicker> { final ColorScheme colorScheme = Theme.of(context).colorScheme; final MaterialLocalizations localizations = MaterialLocalizations.of(context); final TextTheme textTheme = Theme.of(context).textTheme; - final TextStyle? headerStyle = textTheme.caption?.apply( + final TextStyle? headerStyle = textTheme.bodySmall?.apply( color: colorScheme.onSurface.withOpacity(0.60), ); - final TextStyle dayStyle = textTheme.caption!; + final TextStyle dayStyle = textTheme.bodySmall!; final Color enabledDayColor = colorScheme.onSurface.withOpacity(0.87); final Color disabledDayColor = colorScheme.onSurface.withOpacity(0.38); final Color selectedDayColor = colorScheme.onPrimary; @@ -1185,7 +1185,7 @@ class _YearPickerState extends State { } else { textColor = colorScheme.onSurface.withOpacity(0.87); } - final TextStyle? itemStyle = textTheme.bodyText1?.apply(color: textColor); + final TextStyle? itemStyle = textTheme.bodyLarge?.apply(color: textColor); BoxDecoration? decoration; if (isSelected) { diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart index ecc05710eda57..0beb12708da70 100644 --- a/packages/flutter/lib/src/material/checkbox.dart +++ b/packages/flutter/lib/src/material/checkbox.dart @@ -5,6 +5,8 @@ import 'package:flutter/widgets.dart'; import 'checkbox_theme.dart'; +import 'color_scheme.dart'; +import 'colors.dart'; import 'constants.dart'; import 'debug.dart'; import 'material_state.dart'; @@ -91,7 +93,8 @@ class Checkbox extends StatefulWidget { /// Whether this checkbox is checked. /// - /// This property must not be null. + /// When [tristate] is true, a value of null corresponds to the mixed state. + /// When [tristate] is false, this value must not be null. final bool? value; /// Called when the value of the checkbox should change. @@ -382,19 +385,6 @@ class _CheckboxState extends State with TickerProviderStateMixin, Togg }); } - MaterialStateProperty get _defaultFillColor { - final ThemeData themeData = Theme.of(context); - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.disabled)) { - return themeData.disabledColor; - } - if (states.contains(MaterialState.selected)) { - return themeData.colorScheme.secondary; - } - return themeData.unselectedWidgetColor; - }); - } - BorderSide? _resolveSide(BorderSide? side) { if (side is MaterialStateBorderSide) { return MaterialStateProperty.resolveAs(side, states); @@ -408,14 +398,16 @@ class _CheckboxState extends State with TickerProviderStateMixin, Togg @override Widget build(BuildContext context) { assert(debugCheckHasMaterial(context)); - final ThemeData themeData = Theme.of(context); final CheckboxThemeData checkboxTheme = CheckboxTheme.of(context); + final CheckboxThemeData defaults = Theme.of(context).useMaterial3 + ? _CheckboxDefaultsM3(context) + : _CheckboxDefaultsM2(context); final MaterialTapTargetSize effectiveMaterialTapTargetSize = widget.materialTapTargetSize ?? checkboxTheme.materialTapTargetSize - ?? themeData.materialTapTargetSize; + ?? defaults.materialTapTargetSize!; final VisualDensity effectiveVisualDensity = widget.visualDensity ?? checkboxTheme.visualDensity - ?? themeData.visualDensity; + ?? defaults.visualDensity!; Size size; switch (effectiveMaterialTapTargetSize) { case MaterialTapTargetSize.padded: @@ -437,40 +429,48 @@ class _CheckboxState extends State with TickerProviderStateMixin, Togg // so that they can be lerped between. final Set activeStates = states..add(MaterialState.selected); final Set inactiveStates = states..remove(MaterialState.selected); - final Color effectiveActiveColor = widget.fillColor?.resolve(activeStates) + final Color? activeColor = widget.fillColor?.resolve(activeStates) ?? _widgetFillColor.resolve(activeStates) - ?? checkboxTheme.fillColor?.resolve(activeStates) - ?? _defaultFillColor.resolve(activeStates); - final Color effectiveInactiveColor = widget.fillColor?.resolve(inactiveStates) + ?? checkboxTheme.fillColor?.resolve(activeStates); + final Color effectiveActiveColor = activeColor + ?? defaults.fillColor!.resolve(activeStates)!; + final Color? inactiveColor = widget.fillColor?.resolve(inactiveStates) ?? _widgetFillColor.resolve(inactiveStates) - ?? checkboxTheme.fillColor?.resolve(inactiveStates) - ?? _defaultFillColor.resolve(inactiveStates); + ?? checkboxTheme.fillColor?.resolve(inactiveStates); + final Color effectiveInactiveColor = inactiveColor + ?? defaults.fillColor!.resolve(inactiveStates)!; final Set focusedStates = states..add(MaterialState.focused); final Color effectiveFocusOverlayColor = widget.overlayColor?.resolve(focusedStates) ?? widget.focusColor ?? checkboxTheme.overlayColor?.resolve(focusedStates) - ?? themeData.focusColor; + ?? defaults.overlayColor!.resolve(focusedStates)!; final Set hoveredStates = states..add(MaterialState.hovered); final Color effectiveHoverOverlayColor = widget.overlayColor?.resolve(hoveredStates) - ?? widget.hoverColor - ?? checkboxTheme.overlayColor?.resolve(hoveredStates) - ?? themeData.hoverColor; + ?? widget.hoverColor + ?? checkboxTheme.overlayColor?.resolve(hoveredStates) + ?? defaults.overlayColor!.resolve(hoveredStates)!; final Set activePressedStates = activeStates..add(MaterialState.pressed); final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates) - ?? checkboxTheme.overlayColor?.resolve(activePressedStates) - ?? effectiveActiveColor.withAlpha(kRadialReactionAlpha); + ?? checkboxTheme.overlayColor?.resolve(activePressedStates) + ?? activeColor?.withAlpha(kRadialReactionAlpha) + ?? defaults.overlayColor!.resolve(activePressedStates)!; final Set inactivePressedStates = inactiveStates..add(MaterialState.pressed); final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates) - ?? checkboxTheme.overlayColor?.resolve(inactivePressedStates) - ?? effectiveActiveColor.withAlpha(kRadialReactionAlpha); + ?? checkboxTheme.overlayColor?.resolve(inactivePressedStates) + ?? inactiveColor?.withAlpha(kRadialReactionAlpha) + ?? defaults.overlayColor!.resolve(inactivePressedStates)!; final Color effectiveCheckColor = widget.checkColor ?? checkboxTheme.checkColor?.resolve(states) - ?? const Color(0xFFFFFFFF); + ?? defaults.checkColor!.resolve(states)!; + + final double effectiveSplashRadius = widget.splashRadius + ?? checkboxTheme.splashRadius + ?? defaults.splashRadius!; return Semantics( checked: widget.value ?? false, @@ -488,7 +488,7 @@ class _CheckboxState extends State with TickerProviderStateMixin, Togg ..reactionColor = effectiveActivePressedOverlayColor ..hoverColor = effectiveHoverOverlayColor ..focusColor = effectiveFocusOverlayColor - ..splashRadius = widget.splashRadius ?? checkboxTheme.splashRadius ?? kRadialReactionRadius + ..splashRadius = effectiveSplashRadius ..downPosition = downPosition ..isFocused = states.contains(MaterialState.focused) ..isHovered = states.contains(MaterialState.hovered) @@ -682,3 +682,172 @@ class _CheckboxPainter extends ToggleablePainter { } } } + +// Hand coded defaults based on Material Design 2. +class _CheckboxDefaultsM2 extends CheckboxThemeData { + _CheckboxDefaultsM2(BuildContext context) + : _theme = Theme.of(context), + _colors = Theme.of(context).colorScheme; + + final ThemeData _theme; + final ColorScheme _colors; + + @override + MaterialStateProperty get fillColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return _theme.disabledColor; + } + if (states.contains(MaterialState.selected)) { + return _colors.secondary; + } + return _theme.unselectedWidgetColor; + }); + } + + @override + MaterialStateProperty get checkColor { + return MaterialStateProperty.all(const Color(0xFFFFFFFF)); + } + + @override + MaterialStateProperty get overlayColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.pressed)) { + return fillColor.resolve(states).withAlpha(kRadialReactionAlpha); + } + if (states.contains(MaterialState.hovered)) { + return _theme.hoverColor; + } + if (states.contains(MaterialState.focused)) { + return _theme.focusColor; + } + return Colors.transparent; + }); + } + + @override + double get splashRadius => kRadialReactionRadius; + + @override + MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize; + + @override + VisualDensity get visualDensity => _theme.visualDensity; +} + +// BEGIN GENERATED TOKEN PROPERTIES - Checkbox + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Token database version: v0_101 + +class _CheckboxDefaultsM3 extends CheckboxThemeData { + _CheckboxDefaultsM3(BuildContext context) + : _theme = Theme.of(context), + _colors = Theme.of(context).colorScheme; + + final ThemeData _theme; + final ColorScheme _colors; + + @override + MaterialStateProperty get fillColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + if (states.contains(MaterialState.selected)) { + return _colors.onSurface.withOpacity(0.38); + } + return _colors.onSurface.withOpacity(0.38); + } + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return _colors.primary; + } + if (states.contains(MaterialState.hovered)) { + return _colors.primary; + } + if (states.contains(MaterialState.focused)) { + return _colors.primary; + } + return _colors.primary; + } + if (states.contains(MaterialState.pressed)) { + return _colors.onSurface; + } + if (states.contains(MaterialState.hovered)) { + return _colors.onSurface; + } + if (states.contains(MaterialState.focused)) { + return _colors.onSurface; + } + return _colors.onSurface; + }); + } + + @override + MaterialStateProperty get checkColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + if (states.contains(MaterialState.selected)) { + return _colors.surface; + } + return Colors.transparent; // No icons available when the checkbox is unselected. + } + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return _colors.onPrimary; + } + if (states.contains(MaterialState.hovered)) { + return _colors.onPrimary; + } + if (states.contains(MaterialState.focused)) { + return _colors.onPrimary; + } + return _colors.onPrimary; + } + return Colors.transparent; // No icons available when the checkbox is unselected. + }); + } + + @override + MaterialStateProperty get overlayColor { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + if (states.contains(MaterialState.pressed)) { + return _colors.onSurface.withOpacity(0.12); + } + if (states.contains(MaterialState.hovered)) { + return _colors.primary.withOpacity(0.08); + } + if (states.contains(MaterialState.focused)) { + return _colors.primary.withOpacity(0.12); + } + return Colors.transparent; + } + if (states.contains(MaterialState.pressed)) { + return _colors.primary.withOpacity(0.12); + } + if (states.contains(MaterialState.hovered)) { + return _colors.onSurface.withOpacity(0.08); + } + if (states.contains(MaterialState.focused)) { + return _colors.onSurface.withOpacity(0.12); + } + return Colors.transparent; + }); + } + + @override + double get splashRadius => 40.0 / 2; + + @override + MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize; + + @override + VisualDensity get visualDensity => _theme.visualDensity; +} + +// END GENERATED TOKEN PROPERTIES - Checkbox diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 73bd51647534f..76c1cc2633d6f 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -77,7 +77,7 @@ abstract class ChipAttributes { /// The style to be applied to the chip's label. /// - /// The default label style is [TextTheme.bodyText1] from the overall + /// The default label style is [TextTheme.bodyLarge] from the overall /// theme's [ThemeData.textTheme]. // /// This only has an effect on widgets that respect the [DefaultTextStyle], @@ -1167,7 +1167,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final ChipThemeData chipDefaults = widget.defaultProperties ?? ChipThemeData.fromDefaults( brightness: brightness, secondaryColor: brightness == Brightness.dark ? Colors.tealAccent[200]! : theme.primaryColor, - labelStyle: theme.textTheme.bodyText1!, + labelStyle: theme.textTheme.bodyLarge!, ); final TextDirection? textDirection = Directionality.maybeOf(context); final OutlinedBorder resolvedShape = _getShape(theme, chipTheme, chipDefaults); @@ -2068,7 +2068,7 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } // Set this to true to have outlines of the tap targets drawn over - // the chip. This should never be checked in while set to 'true'. + // the chip. This should never be checked in while set to 'true'. static const bool _debugShowTapTargetOutlines = false; @override diff --git a/packages/flutter/lib/src/material/circle_avatar.dart b/packages/flutter/lib/src/material/circle_avatar.dart index 6029e95ba7817..61faac64fd8f9 100644 --- a/packages/flutter/lib/src/material/circle_avatar.dart +++ b/packages/flutter/lib/src/material/circle_avatar.dart @@ -192,7 +192,7 @@ class CircleAvatar extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); final ThemeData theme = Theme.of(context); - TextStyle textStyle = theme.primaryTextTheme.subtitle1!.copyWith(color: foregroundColor); + TextStyle textStyle = theme.primaryTextTheme.titleMedium!.copyWith(color: foregroundColor); Color? effectiveBackgroundColor = backgroundColor; if (effectiveBackgroundColor == null) { switch (ThemeData.estimateBrightnessForColor(textStyle.color!)) { diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index 82f40ace6232f..443c20a8b9fac 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -237,7 +237,7 @@ class DataCell { }) : assert(child != null); /// A cell that has no content and has zero width and height. - static const DataCell empty = DataCell(SizedBox(width: 0.0, height: 0.0)); + static const DataCell empty = DataCell(SizedBox.shrink()); /// The data for the row. /// @@ -515,7 +515,7 @@ class DataTable extends StatelessWidget { /// {@endtemplate} /// /// If null, [DataTableThemeData.dataTextStyle] is used. By default, the text - /// style is [TextTheme.bodyText2]. + /// style is [TextTheme.bodyMedium]. final TextStyle? dataTextStyle; /// {@template flutter.material.dataTable.headingRowColor} @@ -565,7 +565,7 @@ class DataTable extends StatelessWidget { /// {@endtemplate} /// /// If null, [DataTableThemeData.headingTextStyle] is used. By default, the - /// text style is [TextTheme.subtitle2]. + /// text style is [TextTheme.titleSmall]. final TextStyle? headingTextStyle; /// {@template flutter.material.dataTable.horizontalMargin} @@ -774,7 +774,7 @@ class DataTable extends StatelessWidget { final TextStyle effectiveHeadingTextStyle = headingTextStyle ?? dataTableTheme.headingTextStyle ?? themeData.dataTableTheme.headingTextStyle - ?? themeData.textTheme.subtitle2!; + ?? themeData.textTheme.titleSmall!; final double effectiveHeadingRowHeight = headingRowHeight ?? dataTableTheme.headingRowHeight ?? themeData.dataTableTheme.headingRowHeight @@ -837,7 +837,7 @@ class DataTable extends StatelessWidget { final TextStyle effectiveDataTextStyle = dataTextStyle ?? dataTableTheme.dataTextStyle ?? themeData.dataTableTheme.dataTextStyle - ?? themeData.textTheme.bodyText2!; + ?? themeData.textTheme.bodyMedium!; final double effectiveDataRowHeight = dataRowHeight ?? dataTableTheme.dataRowHeight ?? themeData.dataTableTheme.dataRowHeight diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 40881cc81fc25..4823a1fed680e 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -467,8 +467,8 @@ class _DatePickerDialogState extends State with RestorationMix ? colorScheme.onPrimary : colorScheme.onSurface; final TextStyle? dateStyle = orientation == Orientation.landscape - ? textTheme.headline5?.copyWith(color: onPrimarySurface) - : textTheme.headline4?.copyWith(color: onPrimarySurface); + ? textTheme.headlineSmall?.copyWith(color: onPrimarySurface) + : textTheme.headlineMedium?.copyWith(color: onPrimarySurface); final Widget actions = Container( alignment: AlignmentDirectional.centerEnd, @@ -752,7 +752,7 @@ class _DatePickerHeader extends StatelessWidget { final Color primarySurfaceColor = isDark ? colorScheme.surface : colorScheme.primary; final Color onPrimarySurfaceColor = isDark ? colorScheme.onSurface : colorScheme.onPrimary; - final TextStyle? helpStyle = textTheme.overline?.copyWith( + final TextStyle? helpStyle = textTheme.labelSmall?.copyWith( color: onPrimarySurfaceColor, ); @@ -869,7 +869,7 @@ class _DatePickerHeader extends StatelessWidget { /// /// * [helpText], the label displayed at the top of the dialog. /// * [cancelText], the label on the cancel button for the text input mode. -/// * [confirmText],the label on the ok button for the text input mode. +/// * [confirmText],the label on the ok button for the text input mode. /// * [saveText], the label on the save button for the fullscreen calendar /// mode. /// * [errorFormatText], the message used when an input text isn't in a proper @@ -1483,14 +1483,14 @@ class _CalendarRangePickerDialog extends StatelessWidget { final Color headerDisabledForeground = headerForeground.withOpacity(0.38); final String startDateText = _formatRangeStartDate(localizations, selectedStartDate, selectedEndDate); final String endDateText = _formatRangeEndDate(localizations, selectedStartDate, selectedEndDate, DateTime.now()); - final TextStyle? headlineStyle = textTheme.headline5; + final TextStyle? headlineStyle = textTheme.headlineSmall; final TextStyle? startDateStyle = headlineStyle?.apply( color: selectedStartDate != null ? headerForeground : headerDisabledForeground, ); final TextStyle? endDateStyle = headlineStyle?.apply( color: selectedEndDate != null ? headerForeground : headerDisabledForeground, ); - final TextStyle saveButtonStyle = textTheme.button!.apply( + final TextStyle saveButtonStyle = textTheme.labelLarge!.apply( color: onConfirm != null ? headerForeground : headerDisabledForeground, ); @@ -1525,7 +1525,7 @@ class _CalendarRangePickerDialog extends StatelessWidget { children: [ Text( helpText, - style: textTheme.overline!.apply( + style: textTheme.labelSmall!.apply( color: headerForeground, ), ), @@ -1984,7 +1984,7 @@ class _DayHeaders extends StatelessWidget { Widget build(BuildContext context) { final ThemeData themeData = Theme.of(context); final ColorScheme colorScheme = themeData.colorScheme; - final TextStyle textStyle = themeData.textTheme.subtitle2!.apply(color: colorScheme.onSurface); + final TextStyle textStyle = themeData.textTheme.titleSmall!.apply(color: colorScheme.onSurface); final MaterialLocalizations localizations = MaterialLocalizations.of(context); final List labels = _getDayHeaders(textStyle, localizations); @@ -2270,7 +2270,7 @@ class _MonthItemState extends State<_MonthItem> { final bool isDisabled = dayToBuild.isAfter(widget.lastDate) || dayToBuild.isBefore(widget.firstDate); BoxDecoration? decoration; - TextStyle? itemStyle = textTheme.bodyText2; + TextStyle? itemStyle = textTheme.bodyMedium; final bool isRangeSelected = widget.selectedDateStart != null && widget.selectedDateEnd != null; final bool isSelectedDayStart = widget.selectedDateStart != null && dayToBuild.isAtSameMomentAs(widget.selectedDateStart!); @@ -2284,7 +2284,7 @@ class _MonthItemState extends State<_MonthItem> { if (isSelectedDayStart || isSelectedDayEnd) { // The selected start and end dates gets a circle background // highlight, and a contrasting text color. - itemStyle = textTheme.bodyText2?.apply(color: colorScheme.onPrimary); + itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.onPrimary); decoration = BoxDecoration( color: colorScheme.primary, shape: BoxShape.circle, @@ -2308,11 +2308,11 @@ class _MonthItemState extends State<_MonthItem> { textDirection: textDirection, ); } else if (isDisabled) { - itemStyle = textTheme.bodyText2?.apply(color: colorScheme.onSurface.withOpacity(0.38)); + itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.onSurface.withOpacity(0.38)); } else if (DateUtils.isSameDay(widget.currentDate, dayToBuild)) { // The current day gets a different text color and a circle stroke // border. - itemStyle = textTheme.bodyText2?.apply(color: colorScheme.primary); + itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.primary); decoration = BoxDecoration( border: Border.all(color: colorScheme.primary), shape: BoxShape.circle, @@ -2458,7 +2458,7 @@ class _MonthItemState extends State<_MonthItem> { child: ExcludeSemantics( child: Text( localizations.formatMonthYear(widget.displayedMonth), - style: textTheme.bodyText2!.apply(color: themeData.colorScheme.onSurface), + style: textTheme.bodyMedium!.apply(color: themeData.colorScheme.onSurface), ), ), ), @@ -2606,8 +2606,8 @@ class _InputDateRangePickerDialog extends StatelessWidget { ? colorScheme.onPrimary : colorScheme.onSurface; final TextStyle? dateStyle = orientation == Orientation.landscape - ? textTheme.headline5?.apply(color: onPrimarySurfaceColor) - : textTheme.headline4?.apply(color: onPrimarySurfaceColor); + ? textTheme.headlineSmall?.apply(color: onPrimarySurfaceColor) + : textTheme.headlineMedium?.apply(color: onPrimarySurfaceColor); final String dateText = _formatDateRange(context, selectedStartDate, selectedEndDate, currentDate!); final String semanticDateText = selectedStartDate != null && selectedEndDate != null ? '${localizations.formatMediumDate(selectedStartDate!)} – ${localizations.formatMediumDate(selectedEndDate!)}' diff --git a/packages/flutter/lib/src/material/desktop_text_selection.dart b/packages/flutter/lib/src/material/desktop_text_selection.dart index d5e1802def2d3..fbe6848d45136 100644 --- a/packages/flutter/lib/src/material/desktop_text_selection.dart +++ b/packages/flutter/lib/src/material/desktop_text_selection.dart @@ -153,7 +153,7 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect // Don't render the menu until the state of the clipboard is known. if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } final MediaQueryData mediaQuery = MediaQuery.of(context); @@ -196,7 +196,7 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect // If there is no option available, build an empty widget. if (items.isEmpty) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } return _DesktopTextSelectionToolbar( diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index a85dd27d0e1cc..4a5e8dd6e0178 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -334,7 +334,7 @@ class AlertDialog extends StatelessWidget { /// Style for the text in the [title] of this [AlertDialog]. /// /// If null, [DialogTheme.titleTextStyle] is used. If that's null, defaults to - /// [TextTheme.headline6] of [ThemeData.textTheme]. + /// [TextTheme.titleLarge] of [ThemeData.textTheme]. final TextStyle? titleTextStyle; /// The (optional) content of the dialog is displayed in the center of the @@ -363,7 +363,7 @@ class AlertDialog extends StatelessWidget { /// Style for the text in the [content] of this [AlertDialog]. /// /// If null, [DialogTheme.contentTextStyle] is used. If that's null, defaults - /// to [TextTheme.subtitle1] of [ThemeData.textTheme]. + /// to [TextTheme.titleMedium] of [ThemeData.textTheme]. final TextStyle? contentTextStyle; /// The (optional) set of actions that are displayed at the bottom of the @@ -888,7 +888,7 @@ class SimpleDialog extends StatelessWidget { /// Style for the text in the [title] of this [SimpleDialog]. /// /// If null, [DialogTheme.titleTextStyle] is used. If that's null, defaults to - /// [TextTheme.headline6] of [ThemeData.textTheme]. + /// [TextTheme.titleLarge] of [ThemeData.textTheme]. final TextStyle? titleTextStyle; /// The (optional) content of the dialog is displayed in a @@ -922,7 +922,7 @@ class SimpleDialog extends StatelessWidget { /// announce screen transitions when the dialog is opened and closed. /// /// If this label is not provided, a semantic label will be inferred from the - /// [title] if it is not null. If there is no title, the label will be taken + /// [title] if it is not null. If there is no title, the label will be taken /// from [MaterialLocalizations.dialogLabel]. /// /// See also: @@ -976,7 +976,7 @@ class SimpleDialog extends StatelessWidget { bottom: children == null ? effectiveTitlePadding.bottom * paddingScaleFactor : effectiveTitlePadding.bottom, ), child: DefaultTextStyle( - style: titleTextStyle ?? DialogTheme.of(context).titleTextStyle ?? theme.textTheme.headline6!, + style: titleTextStyle ?? DialogTheme.of(context).titleTextStyle ?? theme.textTheme.titleLarge!, child: Semantics( // For iOS platform, the focus always lands on the title. // Set nameRoute to false to avoid title being announce twice. @@ -1297,10 +1297,10 @@ class _DialogDefaultsM2 extends DialogTheme { Color? get backgroundColor => Theme.of(context).dialogBackgroundColor; @override - TextStyle? get titleTextStyle => _textTheme.headline6; + TextStyle? get titleTextStyle => _textTheme.titleLarge; @override - TextStyle? get contentTextStyle => _textTheme.subtitle1; + TextStyle? get contentTextStyle => _textTheme.titleMedium; @override EdgeInsetsGeometry? get actionsPadding => EdgeInsets.zero; diff --git a/packages/flutter/lib/src/material/drawer_header.dart b/packages/flutter/lib/src/material/drawer_header.dart index 4b5a2df6f9f78..bff2c267d87ce 100644 --- a/packages/flutter/lib/src/material/drawer_header.dart +++ b/packages/flutter/lib/src/material/drawer_header.dart @@ -91,7 +91,7 @@ class DrawerHeader extends StatelessWidget { duration: duration, curve: curve, child: child == null ? null : DefaultTextStyle( - style: theme.textTheme.bodyText1!, + style: theme.textTheme.bodyLarge!, child: MediaQuery.removePadding( context: context, removeTop: true, diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index c8e7b151da7f6..764557d720f63 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -1050,7 +1050,7 @@ class DropdownButton extends StatefulWidget { /// ** See code in examples/api/lib/material/dropdown/dropdown_button.style.0.dart ** /// {@end-tool} /// - /// Defaults to the [TextTheme.subtitle1] value of the current + /// Defaults to the [TextTheme.titleMedium] value of the current /// [ThemeData.textTheme] of the current [Theme]. final TextStyle? style; @@ -1266,7 +1266,7 @@ class _DropdownButtonState extends State> with WidgetsBindi } } - TextStyle? get _textStyle => widget.style ?? Theme.of(context).textTheme.subtitle1; + TextStyle? get _textStyle => widget.style ?? Theme.of(context).textTheme.titleMedium; void _handleTap() { final TextDirection? textDirection = Directionality.maybeOf(context); @@ -1334,7 +1334,7 @@ class _DropdownButtonState extends State> with WidgetsBindi // would be clipped. double get _denseButtonHeight { final double textScaleFactor = MediaQuery.of(context).textScaleFactor; - final double fontSize = _textStyle!.fontSize ?? Theme.of(context).textTheme.subtitle1!.fontSize!; + final double fontSize = _textStyle!.fontSize ?? Theme.of(context).textTheme.titleMedium!.fontSize!; final double scaledFontSize = textScaleFactor * fontSize; return math.max(scaledFontSize, math.max(widget.iconSize, _kDenseButtonHeight)); } @@ -1424,7 +1424,7 @@ class _DropdownButtonState extends State> with WidgetsBindi // display the hint or nothing at all. final Widget innerItemsWidget; if (items.isEmpty) { - innerItemsWidget = Container(); + innerItemsWidget = const SizedBox.shrink(); } else { innerItemsWidget = IndexedStack( index: _selectedIndex ?? hintIndex, diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index 399cbd0707b3b..93c93197b5d06 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -22,7 +22,7 @@ import 'theme_data.dart'; /// A Material Design "elevated button". /// /// Use elevated buttons to add dimension to otherwise mostly flat -/// layouts, e.g. in long busy lists of content, or in wide +/// layouts, e.g. in long busy lists of content, or in wide /// spaces. Avoid using elevated buttons on already-elevated content /// such as dialogs or cards. /// @@ -33,7 +33,7 @@ import 'theme_data.dart'; /// background is the [ButtonStyle.backgroundColor]. /// /// The elevated button's default style is defined by -/// [defaultStyleOf]. The style of this elevated button can be +/// [defaultStyleOf]. The style of this elevated button can be /// overridden with its [style] parameter. The style of all elevated /// buttons in a subtree can be overridden with the /// [ElevatedButtonTheme], and the style of all of the elevated @@ -54,8 +54,10 @@ import 'theme_data.dart'; /// /// See also: /// -/// * [TextButton], a simple flat button without a shadow. -/// * [OutlinedButton], a [TextButton] with a border outline. +/// * [FilledButton], a filled button that doesn't elevate when pressed. +/// * [FilledButton.tonal], a filled button variant that uses a secondary fill color. +/// * [OutlinedButton], a button with an outlined border and no fill color. +/// * [TextButton], a button with no outline or fill color. /// * /// * class ElevatedButton extends ButtonStyleButton { @@ -362,7 +364,7 @@ class ElevatedButton extends ButtonStyleButton { disabledForegroundColor: colorScheme.onSurface.withOpacity(0.38), shadowColor: theme.shadowColor, elevation: 2, - textStyle: theme.textTheme.button, + textStyle: theme.textTheme.labelLarge, padding: _scaledPadding(context), minimumSize: const Size(64, 36), maximumSize: Size.infinite, diff --git a/packages/flutter/lib/src/material/elevated_button_theme.dart b/packages/flutter/lib/src/material/elevated_button_theme.dart index dfac0f8220aeb..4b70a5276088b 100644 --- a/packages/flutter/lib/src/material/elevated_button_theme.dart +++ b/packages/flutter/lib/src/material/elevated_button_theme.dart @@ -16,7 +16,7 @@ import 'theme.dart'; /// overall [Theme]'s [ThemeData.elevatedButtonTheme]. /// /// The [style]'s properties override [ElevatedButton]'s default style, -/// i.e. the [ButtonStyle] returned by [ElevatedButton.defaultStyleOf]. Only +/// i.e. the [ButtonStyle] returned by [ElevatedButton.defaultStyleOf]. Only /// the style's non-null property values or resolved non-null /// [MaterialStateProperty] values are used. /// diff --git a/packages/flutter/lib/src/material/expansion_tile.dart b/packages/flutter/lib/src/material/expansion_tile.dart index ece7892e970fc..9014bbd23b269 100644 --- a/packages/flutter/lib/src/material/expansion_tile.dart +++ b/packages/flutter/lib/src/material/expansion_tile.dart @@ -409,7 +409,7 @@ class _ExpansionTileState extends State with SingleTickerProvider _headerColorTween ..begin = widget.collapsedTextColor ?? expansionTileTheme.collapsedTextColor - ?? theme.textTheme.subtitle1!.color + ?? theme.textTheme.titleMedium!.color ..end = widget.textColor ?? expansionTileTheme.textColor ?? colorScheme.primary; _iconColorTween ..begin = widget.collapsedIconColor diff --git a/packages/flutter/lib/src/material/filled_button.dart b/packages/flutter/lib/src/material/filled_button.dart new file mode 100644 index 0000000000000..989e7ca222d1c --- /dev/null +++ b/packages/flutter/lib/src/material/filled_button.dart @@ -0,0 +1,737 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; +import 'dart:ui' show lerpDouble; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import 'button_style.dart'; +import 'button_style_button.dart'; +import 'color_scheme.dart'; +import 'constants.dart'; +import 'filled_button_theme.dart'; +import 'ink_well.dart'; +import 'material_state.dart'; +import 'theme.dart'; +import 'theme_data.dart'; + +enum _FilledButtonVariant { filled, tonal } + +/// A Material Design filled button. +/// +/// Filled buttons have the most visual impact after the [FloatingActionButton], +/// and should be used for important, final actions that complete a flow, +/// like **Save**, **Join now**, or **Confirm**. +/// +/// A filled button is a label [child] displayed on a [Material] +/// widget. The label's [Text] and [Icon] widgets are displayed in +/// [style]'s [ButtonStyle.foregroundColor] and the button's filled +/// background is the [ButtonStyle.backgroundColor]. +/// +/// The filled button's default style is defined by +/// [defaultStyleOf]. The style of this filled button can be +/// overridden with its [style] parameter. The style of all filled +/// buttons in a subtree can be overridden with the +/// [FilledButtonTheme], and the style of all of the filled +/// buttons in an app can be overridden with the [Theme]'s +/// [ThemeData.filledButtonTheme] property. +/// +/// The static [styleFrom] method is a convenient way to create a +/// filled button [ButtonStyle] from simple values. +/// +/// If [onPressed] and [onLongPress] callbacks are null, then the +/// button will be disabled. +/// +/// To create a 'filled tonal' button, use [FilledButton.tonal]. +/// +/// {@tool dartpad} +/// This sample produces enabled and disabled filled and filled tonal +/// buttons. +/// +/// ** See code in examples/api/lib/material/filled_button/filled_button.0.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [OutlinedButton], a button with an outlined border and no fill color. +/// * [TextButton], a button with no outline or fill color. +/// * +/// * +class FilledButton extends ButtonStyleButton { + /// Create a FilledButton. + /// + /// The [autofocus] and [clipBehavior] arguments must not be null. + const FilledButton({ + super.key, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus = false, + super.clipBehavior = Clip.none, + super.statesController, + required super.child, + }) : _variant = _FilledButtonVariant.filled; + + /// Create a filled button from [icon] and [label]. + /// + /// The icon and label are arranged in a row with padding at the start and end + /// and a gap between them. + /// + /// The [icon] and [label] arguments must not be null. + factory FilledButton.icon({ + Key? key, + required VoidCallback? onPressed, + VoidCallback? onLongPress, + ValueChanged? onHover, + ValueChanged? onFocusChange, + ButtonStyle? style, + FocusNode? focusNode, + bool? autofocus, + Clip? clipBehavior, + required Widget icon, + required Widget label, + }) = _FilledButtonWithIcon; + + /// Create a tonal variant of FilledButton. + /// + /// A filled tonal button is an alternative middle ground between + /// [FilledButton] and [OutlinedButton]. They’re useful in contexts where + /// a lower-priority button requires slightly more emphasis than an + /// outline would give, such as "Next" in an onboarding flow. + /// + /// The [autofocus] and [clipBehavior] arguments must not be null. + const FilledButton.tonal({ + super.key, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus = false, + super.clipBehavior = Clip.none, + super.statesController, + required super.child, + }) : _variant = _FilledButtonVariant.tonal; + + /// Create a filled tonal button from [icon] and [label]. + /// + /// The icon and label are arranged in a row with padding at the start and end + /// and a gap between them. + /// + /// The [icon] and [label] arguments must not be null. + factory FilledButton.tonalIcon({ + Key? key, + required VoidCallback? onPressed, + VoidCallback? onLongPress, + ValueChanged? onHover, + ValueChanged? onFocusChange, + ButtonStyle? style, + FocusNode? focusNode, + bool? autofocus, + Clip? clipBehavior, + required Widget icon, + required Widget label, + }) { + return _FilledButtonWithIcon.tonal( + key: key, + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + icon: icon, + label: label, + ); + } + + /// A static convenience method that constructs a filled button + /// [ButtonStyle] given simple values. + /// + /// The [foregroundColor], and [disabledForegroundColor] colors are used to create a + /// [MaterialStateProperty] [ButtonStyle.foregroundColor] value. The + /// [backgroundColor] and [disabledBackgroundColor] are used to create a + /// [MaterialStateProperty] [ButtonStyle.backgroundColor] value. + /// + /// The button's elevations are defined relative to the [elevation] + /// parameter. The disabled elevation is the same as the parameter + /// value, [elevation] + 2 is used when the button is hovered + /// or focused, and elevation + 6 is used when the button is pressed. + /// + /// Similarly, the [enabledMouseCursor] and [disabledMouseCursor] + /// parameters are used to construct [ButtonStyle.mouseCursor]. + /// + /// All of the other parameters are either used directly or used to + /// create a [MaterialStateProperty] with a single value for all + /// states. + /// + /// All parameters default to null, by default this method returns + /// a [ButtonStyle] that doesn't override anything. + /// + /// For example, to override the default text and icon colors for a + /// [FilledButton], as well as its overlay color, with all of the + /// standard opacity adjustments for the pressed, focused, and + /// hovered states, one could write: + /// + /// ```dart + /// FilledButton( + /// style: FilledButton.styleFrom(foregroundColor: Colors.green), + /// onPressed: () {}, + /// child: const Text('Filled button'), + /// ); + /// ``` + /// + /// or for a Filled tonal variant: + /// ```dart + /// FilledButton.tonal( + /// style: FilledButton.styleFrom(foregroundColor: Colors.green), + /// onPressed: () {}, + /// child: const Text('Filled tonal button'), + /// ); + /// ``` + static ButtonStyle styleFrom({ + Color? foregroundColor, + Color? backgroundColor, + Color? disabledForegroundColor, + Color? disabledBackgroundColor, + Color? shadowColor, + Color? surfaceTintColor, + double? elevation, + TextStyle? textStyle, + EdgeInsetsGeometry? padding, + Size? minimumSize, + Size? fixedSize, + Size? maximumSize, + BorderSide? side, + OutlinedBorder? shape, + MouseCursor? enabledMouseCursor, + MouseCursor? disabledMouseCursor, + VisualDensity? visualDensity, + MaterialTapTargetSize? tapTargetSize, + Duration? animationDuration, + bool? enableFeedback, + AlignmentGeometry? alignment, + InteractiveInkFeatureFactory? splashFactory, + }) { + final MaterialStateProperty? backgroundColorProp = + (backgroundColor == null && disabledBackgroundColor == null) + ? null + : _FilledButtonDefaultColor(backgroundColor, disabledBackgroundColor); + final Color? foreground = foregroundColor; + final Color? disabledForeground = disabledForegroundColor; + final MaterialStateProperty? foregroundColorProp = + (foreground == null && disabledForeground == null) + ? null + : _FilledButtonDefaultColor(foreground, disabledForeground); + final MaterialStateProperty? overlayColor = (foreground == null) + ? null + : _FilledButtonDefaultOverlay(foreground); + final MaterialStateProperty? mouseCursor = + (enabledMouseCursor == null && disabledMouseCursor == null) + ? null + : _FilledButtonDefaultMouseCursor(enabledMouseCursor, disabledMouseCursor); + + return ButtonStyle( + textStyle: MaterialStatePropertyAll(textStyle), + backgroundColor: backgroundColorProp, + foregroundColor: foregroundColorProp, + overlayColor: overlayColor, + shadowColor: ButtonStyleButton.allOrNull(shadowColor), + surfaceTintColor: ButtonStyleButton.allOrNull(surfaceTintColor), + elevation: ButtonStyleButton.allOrNull(elevation), + padding: ButtonStyleButton.allOrNull(padding), + minimumSize: ButtonStyleButton.allOrNull(minimumSize), + fixedSize: ButtonStyleButton.allOrNull(fixedSize), + maximumSize: ButtonStyleButton.allOrNull(maximumSize), + side: ButtonStyleButton.allOrNull(side), + shape: ButtonStyleButton.allOrNull(shape), + mouseCursor: mouseCursor, + visualDensity: visualDensity, + tapTargetSize: tapTargetSize, + animationDuration: animationDuration, + enableFeedback: enableFeedback, + alignment: alignment, + splashFactory: splashFactory, + ); + } + + final _FilledButtonVariant _variant; + + /// Defines the button's default appearance. + /// + /// The button [child]'s [Text] and [Icon] widgets are rendered with + /// the [ButtonStyle]'s foreground color. The button's [InkWell] adds + /// the style's overlay color when the button is focused, hovered + /// or pressed. The button's background color becomes its [Material] + /// color. + /// + /// All of the ButtonStyle's defaults appear below. In this list + /// "Theme.foo" is shorthand for `Theme.of(context).foo`. Color + /// scheme values like "onSurface(0.38)" are shorthand for + /// `onSurface.withOpacity(0.38)`. [MaterialStateProperty] valued + /// properties that are not followed by a sublist have the same + /// value for all states, otherwise the values are as specified for + /// each state, and "others" means all other states. + /// + /// The `textScaleFactor` is the value of + /// `MediaQuery.of(context).textScaleFactor` and the names of the + /// EdgeInsets constructors and `EdgeInsetsGeometry.lerp` have been + /// abbreviated for readability. + /// + /// The color of the [ButtonStyle.textStyle] is not used, the + /// [ButtonStyle.foregroundColor] color is used instead. + /// + /// * `textStyle` - Theme.textTheme.labelLarge + /// * `backgroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.12) + /// * others - Theme.colorScheme.secondaryContainer + /// * `foregroundColor` + /// * disabled - Theme.colorScheme.onSurface(0.38) + /// * others - Theme.colorScheme.onSecondaryContainer + /// * `overlayColor` + /// * hovered - Theme.colorScheme.onSecondaryContainer(0.08) + /// * focused or pressed - Theme.colorScheme.onSecondaryContainer(0.12) + /// * `shadowColor` - Theme.colorScheme.shadow + /// * `surfaceTintColor` - null + /// * `elevation` + /// * disabled - 0 + /// * default - 0 + /// * hovered - 1 + /// * focused or pressed - 0 + /// * `padding` + /// * `textScaleFactor <= 1` - horizontal(16) + /// * `1 < textScaleFactor <= 2` - lerp(horizontal(16), horizontal(8)) + /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) + /// * `3 < textScaleFactor` - horizontal(4) + /// * `minimumSize` - Size(64, 40) + /// * `fixedSize` - null + /// * `maximumSize` - Size.infinite + /// * `side` - null + /// * `shape` - StadiumBorder() + /// * `mouseCursor` + /// * disabled - SystemMouseCursors.basic + /// * others - SystemMouseCursors.click + /// * `visualDensity` - Theme.visualDensity + /// * `tapTargetSize` - Theme.materialTapTargetSize + /// * `animationDuration` - kThemeChangeDuration + /// * `enableFeedback` - true + /// * `alignment` - Alignment.center + /// * `splashFactory` - Theme.splashFactory + /// + /// The default padding values for the [FilledButton.icon] factory are slightly different: + /// + /// * `padding` + /// * `textScaleFactor <= 1` - start(12) end(16) + /// * `1 < textScaleFactor <= 2` - lerp(start(12) end(16), horizontal(8)) + /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4)) + /// * `3 < textScaleFactor` - horizontal(4) + /// + /// The default value for `side`, which defines the appearance of the button's + /// outline, is null. That means that the outline is defined by the button + /// shape's [OutlinedBorder.side]. Typically the default value of an + /// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn. + /// + @override + ButtonStyle defaultStyleOf(BuildContext context) { + switch (_variant) { + case _FilledButtonVariant.filled: + return _FilledButtonDefaultsM3(context); + case _FilledButtonVariant.tonal: + return _FilledTonalButtonDefaultsM3(context); + } + } + + /// Returns the [FilledButtonThemeData.style] of the closest + /// [FilledButtonTheme] ancestor. + @override + ButtonStyle? themeStyleOf(BuildContext context) { + return FilledButtonTheme.of(context).style; + } +} + +EdgeInsetsGeometry _scaledPadding(BuildContext context) { + return ButtonStyleButton.scaledPadding( + const EdgeInsets.symmetric(horizontal: 16), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsets.symmetric(horizontal: 4), + MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, + ); +} + +@immutable +class _FilledButtonDefaultColor extends MaterialStateProperty with Diagnosticable { + _FilledButtonDefaultColor(this.color, this.disabled); + + final Color? color; + final Color? disabled; + + @override + Color? resolve(Set states) { + if (states.contains(MaterialState.disabled)) { + return disabled; + } + return color; + } +} + +@immutable +class _FilledButtonDefaultOverlay extends MaterialStateProperty with Diagnosticable { + _FilledButtonDefaultOverlay(this.overlay); + + final Color overlay; + + @override + Color? resolve(Set states) { + if (states.contains(MaterialState.hovered)) { + return overlay.withOpacity(0.08); + } + if (states.contains(MaterialState.focused) || states.contains(MaterialState.pressed)) { + return overlay.withOpacity(0.12); + } + return null; + } +} + +@immutable +class _FilledButtonDefaultMouseCursor extends MaterialStateProperty with Diagnosticable { + _FilledButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor); + + final MouseCursor? enabledCursor; + final MouseCursor? disabledCursor; + + @override + MouseCursor? resolve(Set states) { + if (states.contains(MaterialState.disabled)) { + return disabledCursor; + } + return enabledCursor; + } +} + +class _FilledButtonWithIcon extends FilledButton { + _FilledButtonWithIcon({ + super.key, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + bool? autofocus, + Clip? clipBehavior, + required Widget icon, + required Widget label, + }) : assert(icon != null), + assert(label != null), + super( + autofocus: autofocus ?? false, + clipBehavior: clipBehavior ?? Clip.none, + child: _FilledButtonWithIconChild(icon: icon, label: label) + ); + + _FilledButtonWithIcon.tonal({ + super.key, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + bool? autofocus, + Clip? clipBehavior, + required Widget icon, + required Widget label, + }) : assert(icon != null), + assert(label != null), + super.tonal( + autofocus: autofocus ?? false, + clipBehavior: clipBehavior ?? Clip.none, + child: _FilledButtonWithIconChild(icon: icon, label: label) + ); + + @override + ButtonStyle defaultStyleOf(BuildContext context) { + final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding( + const EdgeInsetsDirectional.fromSTEB(12, 0, 16, 0), + const EdgeInsets.symmetric(horizontal: 8), + const EdgeInsetsDirectional.fromSTEB(8, 0, 4, 0), + MediaQuery.maybeOf(context)?.textScaleFactor ?? 1, + ); + return super.defaultStyleOf(context).copyWith( + padding: MaterialStatePropertyAll(scaledPadding), + ); + } +} + +class _FilledButtonWithIconChild extends StatelessWidget { + const _FilledButtonWithIconChild({ required this.label, required this.icon }); + + final Widget label; + final Widget icon; + + @override + Widget build(BuildContext context) { + final double scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1; + // Adjust the gap based on the text scale factor. Start at 8, and lerp + // to 4 based on how large the text is. + final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; + return Row( + mainAxisSize: MainAxisSize.min, + children: [icon, SizedBox(width: gap), Flexible(child: label)], + ); + } +} + +// BEGIN GENERATED TOKEN PROPERTIES - FilledButton + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Token database version: v0_101 + +class _FilledButtonDefaultsM3 extends ButtonStyle { + _FilledButtonDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty get textStyle => + MaterialStatePropertyAll(Theme.of(context).textTheme.labelLarge); + + @override + MaterialStateProperty? get backgroundColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return _colors.onSurface.withOpacity(0.12); + } + return _colors.primary; + }); + + @override + MaterialStateProperty? get foregroundColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + return _colors.onPrimary; + }); + + @override + MaterialStateProperty? get overlayColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) { + return _colors.onPrimary.withOpacity(0.08); + } + if (states.contains(MaterialState.focused)) { + return _colors.onPrimary.withOpacity(0.12); + } + if (states.contains(MaterialState.pressed)) { + return _colors.onPrimary.withOpacity(0.12); + } + return null; + }); + + @override + MaterialStateProperty? get shadowColor => + ButtonStyleButton.allOrNull(_colors.shadow); + + // No default surface tint color + + @override + MaterialStateProperty? get elevation => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return 0.0; + } + if (states.contains(MaterialState.hovered)) { + return 1.0; + } + if (states.contains(MaterialState.focused)) { + return 0.0; + } + if (states.contains(MaterialState.pressed)) { + return 0.0; + } + return 0.0; + }); + + @override + MaterialStateProperty? get padding => + ButtonStyleButton.allOrNull(_scaledPadding(context)); + + @override + MaterialStateProperty? get minimumSize => + ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + + // No default fixedSize + + @override + MaterialStateProperty? get maximumSize => + ButtonStyleButton.allOrNull(Size.infinite); + + // No default side + + @override + MaterialStateProperty? get shape => + ButtonStyleButton.allOrNull(const StadiumBorder()); + + @override + MaterialStateProperty? get mouseCursor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return SystemMouseCursors.basic; + } + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +// END GENERATED TOKEN PROPERTIES - FilledButton + +// BEGIN GENERATED TOKEN PROPERTIES - FilledTonalButton + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +// Token database version: v0_101 + +class _FilledTonalButtonDefaultsM3 extends ButtonStyle { + _FilledTonalButtonDefaultsM3(this.context) + : super( + animationDuration: kThemeChangeDuration, + enableFeedback: true, + alignment: Alignment.center, + ); + + final BuildContext context; + late final ColorScheme _colors = Theme.of(context).colorScheme; + + @override + MaterialStateProperty get textStyle => + MaterialStatePropertyAll(Theme.of(context).textTheme.labelLarge); + + @override + MaterialStateProperty? get backgroundColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return _colors.onSurface.withOpacity(0.12); + } + return _colors.secondaryContainer; + }); + + @override + MaterialStateProperty? get foregroundColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return _colors.onSurface.withOpacity(0.38); + } + return _colors.onSecondaryContainer; + }); + + @override + MaterialStateProperty? get overlayColor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) { + return _colors.onSecondaryContainer.withOpacity(0.08); + } + if (states.contains(MaterialState.focused)) { + return _colors.onSecondaryContainer.withOpacity(0.12); + } + if (states.contains(MaterialState.pressed)) { + return _colors.onSecondaryContainer.withOpacity(0.12); + } + return null; + }); + + @override + MaterialStateProperty? get shadowColor => + ButtonStyleButton.allOrNull(_colors.shadow); + + // No default surface tint color + + @override + MaterialStateProperty? get elevation => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return 0.0; + } + if (states.contains(MaterialState.hovered)) { + return 1.0; + } + if (states.contains(MaterialState.focused)) { + return 0.0; + } + if (states.contains(MaterialState.pressed)) { + return 0.0; + } + return 0.0; + }); + + @override + MaterialStateProperty? get padding => + ButtonStyleButton.allOrNull(_scaledPadding(context)); + + @override + MaterialStateProperty? get minimumSize => + ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + + // No default fixedSize + + @override + MaterialStateProperty? get maximumSize => + ButtonStyleButton.allOrNull(Size.infinite); + + // No default side + + @override + MaterialStateProperty? get shape => + ButtonStyleButton.allOrNull(const StadiumBorder()); + + @override + MaterialStateProperty? get mouseCursor => + MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return SystemMouseCursors.basic; + } + return SystemMouseCursors.click; + }); + + @override + VisualDensity? get visualDensity => Theme.of(context).visualDensity; + + @override + MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize; + + @override + InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; +} + +// END GENERATED TOKEN PROPERTIES - FilledTonalButton diff --git a/packages/flutter/lib/src/material/filled_button_theme.dart b/packages/flutter/lib/src/material/filled_button_theme.dart new file mode 100644 index 0000000000000..fa7a6d5d56519 --- /dev/null +++ b/packages/flutter/lib/src/material/filled_button_theme.dart @@ -0,0 +1,128 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import 'button_style.dart'; +import 'theme.dart'; + +// Examples can assume: +// late BuildContext context; + +/// A [ButtonStyle] that overrides the default appearance of +/// [FilledButton]s when it's used with [FilledButtonTheme] or with the +/// overall [Theme]'s [ThemeData.filledButtonTheme]. +/// +/// The [style]'s properties override [FilledButton]'s default style, +/// i.e. the [ButtonStyle] returned by [FilledButton.defaultStyleOf]. Only +/// the style's non-null property values or resolved non-null +/// [MaterialStateProperty] values are used. +/// +/// See also: +/// +/// * [FilledButtonTheme], the theme which is configured with this class. +/// * [FilledButton.defaultStyleOf], which returns the default [ButtonStyle] +/// for text buttons. +/// * [FilledButton.styleFrom], which converts simple values into a +/// [ButtonStyle] that's consistent with [FilledButton]'s defaults. +/// * [MaterialStateProperty.resolve], "resolve" a material state property +/// to a simple value based on a set of [MaterialState]s. +/// * [ThemeData.filledButtonTheme], which can be used to override the default +/// [ButtonStyle] for [FilledButton]s below the overall [Theme]. +@immutable +class FilledButtonThemeData with Diagnosticable { + /// Creates an [FilledButtonThemeData]. + /// + /// The [style] may be null. + const FilledButtonThemeData({ this.style }); + + /// Overrides for [FilledButton]'s default style. + /// + /// Non-null properties or non-null resolved [MaterialStateProperty] + /// values override the [ButtonStyle] returned by + /// [FilledButton.defaultStyleOf]. + /// + /// If [style] is null, then this theme doesn't override anything. + final ButtonStyle? style; + + /// Linearly interpolate between two filled button themes. + static FilledButtonThemeData? lerp(FilledButtonThemeData? a, FilledButtonThemeData? b, double t) { + assert (t != null); + if (a == null && b == null) { + return null; + } + return FilledButtonThemeData( + style: ButtonStyle.lerp(a?.style, b?.style, t), + ); + } + + @override + int get hashCode => style.hashCode; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other is FilledButtonThemeData && other.style == style; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('style', style, defaultValue: null)); + } +} + +/// Overrides the default [ButtonStyle] of its [FilledButton] descendants. +/// +/// See also: +/// +/// * [FilledButtonThemeData], which is used to configure this theme. +/// * [FilledButton.defaultStyleOf], which returns the default [ButtonStyle] +/// for filled buttons. +/// * [FilledButton.styleFrom], which converts simple values into a +/// [ButtonStyle] that's consistent with [FilledButton]'s defaults. +/// * [ThemeData.filledButtonTheme], which can be used to override the default +/// [ButtonStyle] for [FilledButton]s below the overall [Theme]. +class FilledButtonTheme extends InheritedTheme { + /// Create a [FilledButtonTheme]. + /// + /// The [data] parameter must not be null. + const FilledButtonTheme({ + super.key, + required this.data, + required super.child, + }) : assert(data != null); + + /// The configuration of this theme. + final FilledButtonThemeData data; + + /// The closest instance of this class that encloses the given context. + /// + /// If there is no enclosing [FilledButtonTheme] widget, then + /// [ThemeData.filledButtonTheme] is used. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// FilledButtonThemeData theme = FilledButtonTheme.of(context); + /// ``` + static FilledButtonThemeData of(BuildContext context) { + final FilledButtonTheme? buttonTheme = context.dependOnInheritedWidgetOfExactType(); + return buttonTheme?.data ?? Theme.of(context).filledButtonTheme; + } + + @override + Widget wrap(BuildContext context, Widget child) { + return FilledButtonTheme(data: data, child: child); + } + + @override + bool updateShouldNotify(FilledButtonTheme oldWidget) => data != oldWidget.data; +} diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index be29b785159a7..aaa566553747d 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -322,7 +322,7 @@ class _FlexibleSpaceBarState extends State { final double opacity = settings.toolbarOpacity; if (opacity > 0.0) { - TextStyle titleStyle = theme.primaryTextTheme.headline6!; + TextStyle titleStyle = theme.primaryTextTheme.titleLarge!; titleStyle = titleStyle.copyWith( color: titleStyle.color!.withOpacity(opacity), ); @@ -415,7 +415,7 @@ class FlexibleSpaceBarSettings extends InheritedWidget { /// /// This value is used by the [AppBar] to resolve /// [AppBar.backgroundColor] against [MaterialState.scrolledUnder], - /// i.e. to enable apps to specify different colors when content + /// i.e. to enable apps to specify different colors when content /// has been scrolled up and behind the app bar. /// /// Null if the caller hasn't determined if the FlexibleSpaceBar diff --git a/packages/flutter/lib/src/material/floating_action_button.dart b/packages/flutter/lib/src/material/floating_action_button.dart index 376acda063b4a..8b051953264e1 100644 --- a/packages/flutter/lib/src/material/floating_action_button.dart +++ b/packages/flutter/lib/src/material/floating_action_button.dart @@ -62,7 +62,7 @@ enum _FloatingActionButtonType { /// /// {@tool dartpad} /// This example shows how to make an extended [FloatingActionButton] in a -/// [Scaffold], with a pink [backgroundColor], a thumbs up [Icon] and a +/// [Scaffold], with a pink [backgroundColor], a thumbs up [Icon] and a /// [Text] label that reads "Approve". /// /// ![](https://flutter.github.io/assets-for-api-docs/assets/material/floating_action_button_label.png) @@ -501,7 +501,7 @@ class FloatingActionButton extends StatelessWidget { /// The text style for an extended [FloatingActionButton]'s label. /// /// If null, [FloatingActionButtonThemeData.extendedTextStyle] is used. If - /// that is also null, then [TextTheme.button] with a letter spacing of 1.2 + /// that is also null, then [TextTheme.labelLarge] with a letter spacing of 1.2 /// is used. final TextStyle? extendedTextStyle; @@ -794,7 +794,7 @@ class _FABDefaultsM2 extends FloatingActionButtonThemeData { @override double? get iconSize => _isLarge ? 36.0 : 24.0; @override EdgeInsetsGeometry? get extendedPadding => EdgeInsetsDirectional.only(start: hasChild && _isExtended ? 16.0 : 20.0, end: 20.0); - @override TextStyle? get extendedTextStyle => _theme.textTheme.button!.copyWith(letterSpacing: 1.2); + @override TextStyle? get extendedTextStyle => _theme.textTheme.labelLarge!.copyWith(letterSpacing: 1.2); } // BEGIN GENERATED TOKEN PROPERTIES - FAB diff --git a/packages/flutter/lib/src/material/grid_tile_bar.dart b/packages/flutter/lib/src/material/grid_tile_bar.dart index e8f923b785d56..d9b3c3223417d 100644 --- a/packages/flutter/lib/src/material/grid_tile_bar.dart +++ b/packages/flutter/lib/src/material/grid_tile_bar.dart @@ -88,13 +88,13 @@ class GridTileBar extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ DefaultTextStyle( - style: darkTheme.textTheme.subtitle1!, + style: darkTheme.textTheme.titleMedium!, softWrap: false, overflow: TextOverflow.ellipsis, child: title!, ), DefaultTextStyle( - style: darkTheme.textTheme.caption!, + style: darkTheme.textTheme.bodySmall!, softWrap: false, overflow: TextOverflow.ellipsis, child: subtitle!, @@ -105,7 +105,7 @@ class GridTileBar extends StatelessWidget { else if (title != null || subtitle != null) Expanded( child: DefaultTextStyle( - style: darkTheme.textTheme.subtitle1!, + style: darkTheme.textTheme.titleMedium!, softWrap: false, overflow: TextOverflow.ellipsis, child: title ?? subtitle!, diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index 3c477204296ab..e196ec9736ea3 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -133,7 +133,7 @@ const double _kMinButtonSize = kMinInteractiveDimension; /// internal default property value. /// /// In Material Design 3, the [IconButton.visualDensity] defaults to [VisualDensity.standard] -/// for all platforms because the button will have a rounded rectangle shape if +/// for all platforms; otherwise the button will have a rounded rectangle shape if /// the [IconButton.visualDensity] is set to [VisualDensity.compact]. Users can /// customize it by using [IconButtonTheme], [IconButton.style] or [IconButton.visualDensity]. /// diff --git a/packages/flutter/lib/src/material/ink_decoration.dart b/packages/flutter/lib/src/material/ink_decoration.dart index 8529cfbc56e31..8cdad3d993003 100644 --- a/packages/flutter/lib/src/material/ink_decoration.dart +++ b/packages/flutter/lib/src/material/ink_decoration.dart @@ -292,7 +292,7 @@ class _InkState extends State { _ink!.decoration = widget.decoration; _ink!.configuration = createLocalImageConfiguration(context); } - return widget.child ?? Container(); + return widget.child ?? const SizedBox(); } @override @@ -334,12 +334,11 @@ class InkDecoration extends InkFeature { InkDecoration({ required Decoration? decoration, required ImageConfiguration configuration, - required MaterialInkController controller, + required super.controller, required super.referenceBox, super.onRemoved, }) : assert(configuration != null), - _configuration = configuration, - super(controller: controller) { + _configuration = configuration { this.decoration = decoration; controller.addInkFeature(this); } diff --git a/packages/flutter/lib/src/material/ink_highlight.dart b/packages/flutter/lib/src/material/ink_highlight.dart index 892012fef2f66..76d0c382c8452 100644 --- a/packages/flutter/lib/src/material/ink_highlight.dart +++ b/packages/flutter/lib/src/material/ink_highlight.dart @@ -37,9 +37,9 @@ class InkHighlight extends InteractiveInkFeature { /// /// When the highlight is removed, `onRemoved` will be called. InkHighlight({ - required MaterialInkController controller, + required super.controller, required super.referenceBox, - required Color color, + required super.color, required TextDirection textDirection, BoxShape shape = BoxShape.rectangle, double? radius, @@ -57,8 +57,7 @@ class InkHighlight extends InteractiveInkFeature { _borderRadius = borderRadius ?? BorderRadius.zero, _customBorder = customBorder, _textDirection = textDirection, - _rectCallback = rectCallback, - super(controller: controller, color: color) { + _rectCallback = rectCallback { _alphaController = AnimationController(duration: fadeDuration, vsync: controller.vsync) ..addListener(controller.markNeedsPaint) ..addStatusListener(_handleAlphaStatusChanged) diff --git a/packages/flutter/lib/src/material/ink_sparkle.dart b/packages/flutter/lib/src/material/ink_sparkle.dart index 423358cfb2c71..043af8a074d11 100644 --- a/packages/flutter/lib/src/material/ink_sparkle.dart +++ b/packages/flutter/lib/src/material/ink_sparkle.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:math' as math; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; @@ -99,8 +98,8 @@ class InkSparkle extends InteractiveInkFeature { /// identified in the shader as "noise", and the sparkles are derived from /// pseudorandom triangular noise. InkSparkle({ - required MaterialInkController controller, - required RenderBox referenceBox, + required super.controller, + required super.referenceBox, required super.color, required Offset position, required TextDirection textDirection, @@ -117,18 +116,18 @@ class InkSparkle extends InteractiveInkFeature { _borderRadius = borderRadius ?? BorderRadius.zero, _customBorder = customBorder, _textDirection = textDirection, - _targetRadius = (radius ?? _getTargetRadius(referenceBox, containedInkWell, rectCallback, position)) * _targetRadiusMultiplier, - _clipCallback = _getClipCallback(referenceBox, containedInkWell, rectCallback), - super(controller: controller, referenceBox: referenceBox) { + _targetRadius = (radius ?? _getTargetRadius( + referenceBox, + containedInkWell, + rectCallback, + position, + ) + ) * _targetRadiusMultiplier, + _clipCallback = _getClipCallback(referenceBox, containedInkWell, rectCallback) { // InkSparkle will not be painted until the async compilation completes. - _InkSparkleFactory.compileShaderIfNeccessary(); + _InkSparkleFactory.initializeShader(); controller.addInkFeature(this); - // All animation values are derived from Android 12 source code. See: - // - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java - // - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleDrawable.java - // - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleAnimationSession.java - // Immediately begin animating the ink. _animationController = AnimationController( duration: _animationDuration, @@ -242,6 +241,9 @@ class InkSparkle extends InteractiveInkFeature { final RectCallback? _clipCallback; final TextDirection _textDirection; + late final ui.FragmentShader _fragmentShader; + bool _fragmentShaderInitialized = false; + /// Used to specify this type of ink splash for an [InkWell], [InkResponse], /// material [Theme], or [ButtonStyle]. /// @@ -260,6 +262,9 @@ class InkSparkle extends InteractiveInkFeature { void dispose() { _animationController.stop(); _animationController.dispose(); + if (_fragmentShaderInitialized) { + _fragmentShader.dispose(); + } super.dispose(); } @@ -268,13 +273,18 @@ class InkSparkle extends InteractiveInkFeature { assert(_animationController.isAnimating); // InkSparkle can only paint if its shader has been compiled. - if (_InkSparkleFactory._shaderManager == null) { + if (_InkSparkleFactory._program == null) { // Skipping paintFeature because the shader it relies on is not ready to - // be used. InkSparkleFactory.compileShaderIfNeccessary must complete + // be used. InkSparkleFactory.initializeShader must complete // before InkSparkle can paint. return; } + if (!_fragmentShaderInitialized) { + _fragmentShader = _InkSparkleFactory._program!.fragmentShader(); + _fragmentShaderInitialized = true; + } + canvas.save(); _transformCanvas(canvas: canvas, transform: transform); if (_clipCallback != null) { @@ -287,7 +297,9 @@ class InkSparkle extends InteractiveInkFeature { ); } - final Paint paint = Paint()..shader = _createRippleShader(); + _updateFragmentShader(); + + final Paint paint = Paint()..shader = _fragmentShader; if (_clipCallback != null) { canvas.drawRect(_clipCallback!(), paint); } else { @@ -299,12 +311,13 @@ class InkSparkle extends InteractiveInkFeature { double get _width => referenceBox.size.width; double get _height => referenceBox.size.height; + /// All double values for uniforms come from the Android 12 ripple /// implementation from the following files: /// - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java /// - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleDrawable.java /// - https://cs.android.com/android/platform/superproject/+/master:frameworks/base/graphics/java/android/graphics/drawable/RippleAnimationSession.java - Shader _createRippleShader() { + void _updateFragmentShader() { const double turbulenceScale = 1.5; final double turbulencePhase = _turbulenceSeed + _radiusScale.value; final double noisePhase = turbulencePhase; @@ -312,55 +325,56 @@ class InkSparkle extends InteractiveInkFeature { final double rotation2 = turbulencePhase * _rotateLeft + 2.0 * math.pi; final double rotation3 = turbulencePhase * _rotateRight + 2.75 * math.pi; - return _InkSparkleFactory._shaderManager!.shader( - // The following uniforms are the same throughout the animation. - uColor: _colorToVector4(_color), - uSparkleColor: Vector4(1.0, 1.0, 1.0, 1.0), - uBlur: 1.0, - uMaxRadius: _targetRadius, - uResolutionScale: Vector2(1.0 / _width, 1.0 / _height), - uNoiseScale: Vector2(_noiseDensity / _width, _noiseDensity / _height), - - // The following uniforms update each frame of the animation. - uCenter: _center.value, - uRadiusScale: _radiusScale.value, - uAlpha: _alpha.value, - uSparkleAlpha: _sparkleAlpha.value, - - // The following uniforms are driven by the turbulence phase and change - // each frame of the animation. These uniforms are uses to modify the - // default (if these fields are unset or 0) circular outer ring to a - // non-uniform shape that is more like an actual ink splash. In addition - // to the positional based triangular noise created in the shader, these - // uniforms also vary the appearance of the sparkles even when the same - // location is tapped. - uTurbulencePhase: turbulencePhase, - uNoisePhase: noisePhase / 1000.0, - uCircle1: Vector2( - turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.cos(turbulenceScale * 0.55)), - turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.sin(turbulenceScale * 0.55)), - ), - uCircle2: Vector2( - turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.45)), - turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.45)), - ), - uCircle3: Vector2( - turbulenceScale + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.35)), - turbulenceScale + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.35)), - ), - uRotation1: Vector2(math.cos(rotation1), math.sin(rotation1)), - uRotation2: Vector2(math.cos(rotation2), math.sin(rotation2)), - uRotation3: Vector2(math.cos(rotation3), math.sin(rotation3)), - ); - } - - Vector4 _colorToVector4(Color color) { - return Vector4( - color.red / 255.0, - color.blue / 255.0, - color.green / 255.0, - color.alpha / 255.0, - ); + _fragmentShader + // uColor + ..setFloat(0, _color.red / 255.0) + ..setFloat(1, _color.green / 255.0) + ..setFloat(2, _color.blue / 255.0) + ..setFloat(3, _color.alpha / 255.0) + // uAlpha + ..setFloat(4, _alpha.value) + // uSparkleColor + ..setFloat(5, 1.0) + ..setFloat(6, 1.0) + ..setFloat(7, 1.0) + ..setFloat(8, 1.0) + // uSparkleAlpha + ..setFloat(9, _sparkleAlpha.value) + // uBlur + ..setFloat(10, 1.0) + // uCenter + ..setFloat(11, _center.value.x) + ..setFloat(12, _center.value.y) + // uRadiusScale + ..setFloat(13, _radiusScale.value) + // uMaxRadius + ..setFloat(14, _targetRadius) + // uResolutionScale + ..setFloat(15, 1.0 / _width) + ..setFloat(16, 1.0 / _height) + // uNoiseScale + ..setFloat(17, _noiseDensity / _width) + ..setFloat(18, _noiseDensity / _height) + // uNoisePhase + ..setFloat(19, noisePhase / 1000.0) + // uCircle1 + ..setFloat(20, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.cos(turbulenceScale * 0.55))) + ..setFloat(21, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.sin(turbulenceScale * 0.55))) + // uCircle2 + ..setFloat(22, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.45))) + ..setFloat(23, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.45))) + // uCircle3 + ..setFloat(24, turbulenceScale + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.35))) + ..setFloat(25, turbulenceScale + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.35))) + // uRotation1 + ..setFloat(26, math.cos(rotation1)) + ..setFloat(27, math.sin(rotation1)) + // uRotation2 + ..setFloat(28, math.cos(rotation2)) + ..setFloat(29, math.sin(rotation2)) + // uRotation3 + ..setFloat(30, math.cos(rotation3)) + ..setFloat(31, math.sin(rotation3)); } /// Transforms the canvas for an ink feature to be painted on the [canvas]. @@ -430,17 +444,19 @@ class _InkSparkleFactory extends InteractiveInkFeatureFactory { const _InkSparkleFactory.constantTurbulenceSeed() : turbulenceSeed = 1337.0; - static void compileShaderIfNeccessary() { + static void initializeShader() { if (!_initCalled) { - FragmentShaderManager.inkSparkle().then((FragmentShaderManager manager) { - _shaderManager = manager; - }); + ui.FragmentProgram.fromAsset('shaders/ink_sparkle.frag').then( + (ui.FragmentProgram program) { + _program = program; + }, + ); _initCalled = true; } } static bool _initCalled = false; - static FragmentShaderManager? _shaderManager; + static ui.FragmentProgram? _program; final double? turbulenceSeed; @@ -501,74 +517,3 @@ double _getTargetRadius( final double d2 = (size.topRight(Offset.zero) - size.bottomLeft(Offset.zero)).distance; return math.max(d1, d2) / 2.0; } - -// The code below is generated by the package: fragment_shader_manager. -// It is hand modified to update for flutter/flutter style and asset loading. - -/// A generated class for managing [FragmentProgram] that includes a -/// pre-transpiled shader program into SPIR-V. -/// -/// See: -/// - https://github.com/material-components/material-components-flutter-experimental/tree/fragment-shader-manager/fragment_shader_manager -/// -/// GLSL source for this shader is under `shaders/ink_sparkle.frag`. -class FragmentShaderManager { - FragmentShaderManager._(); - - static late ui.FragmentProgram _program; - - /// Creates an [FragmentShaderManager] with an [InkSparkle] effect. - static Future inkSparkle() async { - final FragmentShaderManager manager = FragmentShaderManager._(); - _program = await ui.FragmentProgram.fromAsset( - 'shaders/ink_sparkle.frag', - ); - return manager; - } - - /// Creates a shader with the original program and optional uniforms. - /// - /// A new shader must be made whenever the uniforms are updated. - Shader shader({ - Vector4? uColor, - double? uAlpha, - Vector4? uSparkleColor, - double? uSparkleAlpha, - double? uBlur, - Vector2? uCenter, - double? uRadiusScale, - double? uMaxRadius, - Vector2? uResolutionScale, - Vector2? uNoiseScale, - double? uNoisePhase, - double? uTurbulencePhase, - Vector2? uCircle1, - Vector2? uCircle2, - Vector2? uCircle3, - Vector2? uRotation1, - Vector2? uRotation2, - Vector2? uRotation3, - }) { - return _program.shader( - floatUniforms: Float32List.fromList([ - ...uColor != null ? uColor.storage : [0, 0, 0, 0], - ...uAlpha != null ? [uAlpha] : [0], - ...uSparkleColor != null ? uSparkleColor.storage : [0, 0, 0, 0], - ...uSparkleAlpha != null ? [uSparkleAlpha] : [0], - ...uBlur != null ? [uBlur] : [0], - ...uCenter != null ? uCenter.storage : [0, 0], - ...uRadiusScale != null ? [uRadiusScale] : [0], - ...uMaxRadius != null ? [uMaxRadius] : [0], - ...uResolutionScale != null ? uResolutionScale.storage : [0, 0], - ...uNoiseScale != null ? uNoiseScale.storage : [0, 0], - ...uNoisePhase != null ? [uNoisePhase] : [0], - ...uCircle1 != null ? uCircle1.storage : [0, 0], - ...uCircle2 != null ? uCircle2.storage : [0, 0], - ...uCircle3 != null ? uCircle3.storage : [0, 0], - ...uRotation1 != null ? uRotation1.storage : [0, 0], - ...uRotation2 != null ? uRotation2.storage : [0, 0], - ...uRotation3 != null ? uRotation3.storage : [0, 0], - ]), - ); - } -} diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 1fee93405f7cb..d343605e6a2db 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -501,7 +501,7 @@ class InkResponse extends StatelessWidget { /// [MaterialState.pressed] triggers a ripple (an ink splash), per /// the current Material Design spec. The [overlayColor] doesn't map /// a state to [highlightColor] because a separate highlight is not - /// used by the current design guidelines. See + /// used by the current design guidelines. See /// https://material.io/design/interaction/states.html#pressed /// /// If the overlay color is null or resolves to null, then [focusColor], diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 48def3297f4c6..cceb50d175458 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -319,7 +319,7 @@ class _HelperError extends StatefulWidget { class _HelperErrorState extends State<_HelperError> with SingleTickerProviderStateMixin { // If the height of this widget and the counter are zero ("empty") at // layout time, no space is allocated for the subtext. - static const Widget empty = SizedBox(); + static const Widget empty = SizedBox.shrink(); late AnimationController _controller; Widget? _helper; @@ -1761,7 +1761,7 @@ class InputDecorator extends StatefulWidget { /// The style on which to base the label, hint, counter, and error styles /// if the [decoration] does not provide explicit styles. /// - /// If null, `baseStyle` defaults to the `subtitle1` style from the + /// If null, `baseStyle` defaults to the `titleMedium` style from the /// current [Theme], see [ThemeData.textTheme]. /// /// The [TextStyle.textBaseline] of the [baseStyle] is used to determine @@ -1957,7 +1957,7 @@ class _InputDecoratorState extends State with TickerProviderStat : themeData.disabledColor; } if (decoration.errorText != null) { - return themeData.errorColor; + return themeData.colorScheme.error; } if (isFocused) { return themeData.colorScheme.primary; @@ -1991,17 +1991,20 @@ class _InputDecoratorState extends State with TickerProviderStat } Color _getIconColor(ThemeData themeData, InputDecorationTheme defaults) { - return MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.iconColor, materialState) + return MaterialStateProperty.resolveAs(decoration.iconColor, materialState) + ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.iconColor, materialState) ?? MaterialStateProperty.resolveAs(defaults.iconColor!, materialState); } Color _getPrefixIconColor(ThemeData themeData, InputDecorationTheme defaults) { - return MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.prefixIconColor, materialState) + return MaterialStateProperty.resolveAs(decoration.prefixIconColor, materialState) + ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.prefixIconColor, materialState) ?? MaterialStateProperty.resolveAs(defaults.prefixIconColor!, materialState); } Color _getSuffixIconColor(ThemeData themeData, InputDecorationTheme defaults) { - return MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.suffixIconColor, materialState) + return MaterialStateProperty.resolveAs(decoration.suffixIconColor, materialState) + ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.suffixIconColor, materialState) ?? MaterialStateProperty.resolveAs(defaults.suffixIconColor!, materialState); } @@ -2026,7 +2029,7 @@ class _InputDecoratorState extends State with TickerProviderStat final TextStyle? style = MaterialStateProperty.resolveAs(decoration.labelStyle, materialState) ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.labelStyle, materialState); - return themeData.textTheme.subtitle1! + return themeData.textTheme.titleMedium! .merge(widget.baseStyle) .merge(defaultStyle) .merge(style) @@ -2041,7 +2044,7 @@ class _InputDecoratorState extends State with TickerProviderStat final TextStyle? style = MaterialStateProperty.resolveAs(decoration.hintStyle, materialState) ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.hintStyle, materialState); - return themeData.textTheme.subtitle1! + return themeData.textTheme.titleMedium! .merge(widget.baseStyle) .merge(defaultStyle) .merge(style); @@ -2057,7 +2060,7 @@ class _InputDecoratorState extends State with TickerProviderStat final TextStyle? style = MaterialStateProperty.resolveAs(decoration.floatingLabelStyle, materialState) ?? MaterialStateProperty.resolveAs(themeData.inputDecorationTheme.floatingLabelStyle, materialState); - return themeData.textTheme.subtitle1! + return themeData.textTheme.titleMedium! .merge(widget.baseStyle) .copyWith(height: 1) .merge(defaultTextStyle) @@ -2638,7 +2641,7 @@ class InputDecoration { /// /// Note that if you specify this style it will override the default behavior /// of [InputDecoration] that changes the color of the label to the - /// [InputDecoration.errorStyle] color or [ThemeData.errorColor]. + /// [InputDecoration.errorStyle] color or [ColorScheme.error]. /// /// {@tool dartpad} /// It's possible to override the label style for just the error state, or @@ -2668,7 +2671,7 @@ class InputDecoration { /// /// Note that if you specify this style it will override the default behavior /// of [InputDecoration] that changes the color of the label to the - /// [InputDecoration.errorStyle] color or [ThemeData.errorColor]. + /// [InputDecoration.errorStyle] color or [ColorScheme.error]. /// /// {@tool dartpad} /// It's possible to override the label style for just the error state, or @@ -3121,7 +3124,7 @@ class InputDecoration { final String? counterText; /// Optional custom counter widget to go in the place otherwise occupied by - /// [counterText]. If this property is non null, then [counterText] is + /// [counterText]. If this property is non null, then [counterText] is /// ignored. final Widget? counter; @@ -3314,7 +3317,7 @@ class InputDecoration { /// If [border] derives from [InputBorder] the border's [InputBorder.borderSide], /// i.e. the border's color and width, will be overridden to reflect the input /// decorator's state. Only the border's shape is used. If custom [BorderSide] - /// values are desired for a given state, all four borders – [errorBorder], + /// values are desired for a given state, all four borders – [errorBorder], /// [focusedBorder], [enabledBorder], [disabledBorder] – must be set. /// /// The decoration's container is the area which is filled if [filled] is @@ -4342,7 +4345,7 @@ class _InputDecoratorDefaultsM2 extends InputDecorationTheme { return TextStyle(color: Theme.of(context).disabledColor); } if (states.contains(MaterialState.error)) { - return TextStyle(color: Theme.of(context).errorColor); + return TextStyle(color: Theme.of(context).colorScheme.error); } if (states.contains(MaterialState.focused)) { return TextStyle(color: Theme.of(context).colorScheme.primary); @@ -4354,19 +4357,19 @@ class _InputDecoratorDefaultsM2 extends InputDecorationTheme { TextStyle? get helperStyle => MaterialStateTextStyle.resolveWith((Set states) { final ThemeData themeData= Theme.of(context); if (states.contains(MaterialState.disabled)) { - return themeData.textTheme.caption!.copyWith(color: Colors.transparent); + return themeData.textTheme.bodySmall!.copyWith(color: Colors.transparent); } - return themeData.textTheme.caption!.copyWith(color: themeData.hintColor); + return themeData.textTheme.bodySmall!.copyWith(color: themeData.hintColor); }); @override TextStyle? get errorStyle => MaterialStateTextStyle.resolveWith((Set states) { final ThemeData themeData= Theme.of(context); if (states.contains(MaterialState.disabled)) { - return themeData.textTheme.caption!.copyWith(color: Colors.transparent); + return themeData.textTheme.bodySmall!.copyWith(color: Colors.transparent); } - return themeData.textTheme.caption!.copyWith(color: themeData.errorColor); + return themeData.textTheme.bodySmall!.copyWith(color: themeData.colorScheme.error); }); @override diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart index dc207507650f0..cc5ec41436899 100644 --- a/packages/flutter/lib/src/material/list_tile.dart +++ b/packages/flutter/lib/src/material/list_tile.dart @@ -23,8 +23,8 @@ import 'theme_data.dart'; /// Defines the title font used for [ListTile] descendants of a [ListTileTheme]. /// -/// List tiles that appear in a [Drawer] use the theme's [TextTheme.bodyText1] -/// text style, which is a little smaller than the theme's [TextTheme.subtitle1] +/// List tiles that appear in a [Drawer] use the theme's [TextTheme.bodyLarge] +/// text style, which is a little smaller than the theme's [TextTheme.titleMedium] /// text style, which is used by default. enum ListTileStyle { /// Use a title font that's appropriate for a [ListTile] in a list. @@ -286,6 +286,7 @@ class ListTile extends StatelessWidget { this.selected = false, this.focusColor, this.hoverColor, + this.splashColor, this.focusNode, this.autofocus = false, this.tileColor, @@ -323,14 +324,14 @@ class ListTile extends StatelessWidget { /// two lines. For example, you can use [Text.maxLines] to enforce the number /// of lines. /// - /// The subtitle's default [TextStyle] depends on [TextTheme.bodyText2] except + /// The subtitle's default [TextStyle] depends on [TextTheme.bodyMedium] except /// [TextStyle.color]. The [TextStyle.color] depends on the value of [enabled] /// and [selected]. /// /// When [enabled] is false, the text color is set to [ThemeData.disabledColor]. /// /// When [selected] is false, the text color is set to [ListTileTheme.textColor] - /// if it's not null and to [TextTheme.caption]'s color if [ListTileTheme.textColor] + /// if it's not null and to [TextTheme.bodySmall]'s color if [ListTileTheme.textColor] /// is null. final Widget? subtitle; @@ -495,6 +496,9 @@ class ListTile extends StatelessWidget { /// The color for the tile's [Material] when a pointer is hovering over it. final Color? hoverColor; + /// The color of splash for the tile's [Material]. + final Color? splashColor; + /// {@macro flutter.widgets.Focus.focusNode} final FocusNode? focusNode; @@ -589,7 +593,13 @@ class ListTile extends StatelessWidget { return selectedColor ?? tileTheme.selectedColor ?? theme.listTileTheme.selectedColor ?? theme.colorScheme.primary; } - final Color? color = iconColor ?? tileTheme.iconColor ?? theme.listTileTheme.iconColor; + final Color? color = iconColor + ?? tileTheme.iconColor + ?? theme.listTileTheme.iconColor + // If [ThemeData.useMaterial3] is set to true the disabled icon color + // will be set to Theme.colorScheme.onSurface(0.38), if false, defaults to null, + // as described in: https://m3.material.io/components/icon-buttons/specs. + ?? (theme.useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.38) : null); if (color != null) { return color; } @@ -624,10 +634,10 @@ class ListTile extends StatelessWidget { final TextStyle textStyle; switch(style ?? tileTheme.style ?? theme.listTileTheme.style ?? ListTileStyle.list) { case ListTileStyle.drawer: - textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyText1!; + textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyLarge!; break; case ListTileStyle.list: - textStyle = theme.useMaterial3 ? theme.textTheme.titleMedium! : theme.textTheme.subtitle1!; + textStyle = theme.useMaterial3 ? theme.textTheme.titleMedium! : theme.textTheme.titleMedium!; break; } final Color? color = _textColor(theme, tileTheme, textStyle.color); @@ -637,11 +647,11 @@ class ListTile extends StatelessWidget { } TextStyle _subtitleTextStyle(ThemeData theme, ListTileThemeData tileTheme) { - final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyText2!; + final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyMedium!; final Color? color = _textColor( theme, tileTheme, - theme.useMaterial3 ? theme.textTheme.bodySmall!.color : theme.textTheme.caption!.color, + theme.useMaterial3 ? theme.textTheme.bodySmall!.color : theme.textTheme.bodySmall!.color, ); return _isDenseLayout(theme, tileTheme) ? textStyle.copyWith(color: color, fontSize: 12.0) @@ -649,7 +659,7 @@ class ListTile extends StatelessWidget { } TextStyle _trailingAndLeadingTextStyle(ThemeData theme, ListTileThemeData tileTheme) { - final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyText2!; + final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyMedium!; final Color? color = _textColor(theme, tileTheme, textStyle.color); return textStyle.copyWith(color: color); } @@ -733,6 +743,7 @@ class ListTile extends StatelessWidget { focusNode: focusNode, focusColor: focusColor, hoverColor: hoverColor, + splashColor: splashColor, autofocus: autofocus, enableFeedback: enableFeedback ?? tileTheme.enableFeedback ?? true, child: Semantics( diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 15b1ce3c80dd0..1194a0f1bc498 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -417,7 +417,7 @@ class _MaterialState extends State with TickerProviderStateMixin { Widget? contents = widget.child; if (contents != null) { contents = AnimatedDefaultTextStyle( - style: widget.textStyle ?? Theme.of(context).textTheme.bodyText2!, + style: widget.textStyle ?? Theme.of(context).textTheme.bodyMedium!, duration: widget.animationDuration, child: contents, ); diff --git a/packages/flutter/lib/src/material/material_button.dart b/packages/flutter/lib/src/material/material_button.dart index 67dbc1da71016..9a20732463cea 100644 --- a/packages/flutter/lib/src/material/material_button.dart +++ b/packages/flutter/lib/src/material/material_button.dart @@ -130,7 +130,7 @@ class MaterialButton extends StatelessWidget { /// The color to use for this button's text. /// /// The button's [Material.textStyle] will be the current theme's button text - /// style, [TextTheme.button] of [ThemeData.textTheme], configured with this + /// style, [TextTheme.labelLarge] of [ThemeData.textTheme], configured with this /// color. /// /// The default text color depends on the button theme's text theme, @@ -148,7 +148,7 @@ class MaterialButton extends StatelessWidget { /// The color to use for this button's text when the button is disabled. /// /// The button's [Material.textStyle] will be the current theme's button text - /// style, [TextTheme.button] of [ThemeData.textTheme], configured with this + /// style, [TextTheme.labelLarge] of [ThemeData.textTheme], configured with this /// color. /// /// The default value is the theme's disabled color, @@ -395,7 +395,7 @@ class MaterialButton extends StatelessWidget { onHighlightChanged: onHighlightChanged, mouseCursor: mouseCursor, fillColor: buttonTheme.getFillColor(this), - textStyle: theme.textTheme.button!.copyWith(color: buttonTheme.getTextColor(this)), + textStyle: theme.textTheme.labelLarge!.copyWith(color: buttonTheme.getTextColor(this)), focusColor: focusColor ?? buttonTheme.getFocusColor(this), hoverColor: hoverColor ?? buttonTheme.getHoverColor(this), highlightColor: highlightColor ?? theme.highlightColor, diff --git a/packages/flutter/lib/src/material/material_state.dart b/packages/flutter/lib/src/material/material_state.dart index 332c65783d04c..71bc743e8c277 100644 --- a/packages/flutter/lib/src/material/material_state.dart +++ b/packages/flutter/lib/src/material/material_state.dart @@ -604,8 +604,8 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord /// of [MaterialState]s. /// /// Material state properties represent values that depend on a widget's material -/// "state". The state is encoded as a set of [MaterialState] values, like -/// [MaterialState.focused], [MaterialState.hovered], [MaterialState.pressed]. For +/// "state". The state is encoded as a set of [MaterialState] values, like +/// [MaterialState.focused], [MaterialState.hovered], [MaterialState.pressed]. For /// example the [InkWell.overlayColor] defines the color that fills the ink well /// when it's pressed (the "splash color"), focused, or hovered. The [InkWell] /// uses the overlay color's [resolve] method to compute the color for the @@ -613,7 +613,7 @@ class _MaterialStateUnderlineInputBorder extends MaterialStateUnderlineInputBord /// /// [ButtonStyle], which is used to configure the appearance of /// buttons like [TextButton], [ElevatedButton], and [OutlinedButton], -/// has many material state properties. The button widgets keep track +/// has many material state properties. The button widgets keep track /// of their current material state and [resolve] the button style's /// material state properties when their value is needed. /// diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index 85cc7e2c3637f..7fd5e24425b38 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -268,7 +268,7 @@ class NavigationDestination extends StatelessWidget { /// /// The accompanying [Text] widget will use /// [NavigationBarThemeData.labelTextStyle]. If this are null, the default - /// text style would use [TextTheme.overline] with [ColorScheme.onSurface]. + /// text style would use [TextTheme.labelSmall] with [ColorScheme.onSurface]. final String label; /// The text to display in the tooltip for this [NavigationDestination], when @@ -382,7 +382,7 @@ class _NavigationDestinationBuilder extends StatelessWidget { /// Builds the label for an destination in a [NavigationBar]. /// /// To animate between unselected and selected, build the icon based on - /// [_NavigationDestinationInfo.selectedAnimation]. When the animation is + /// [_NavigationDestinationInfo.selectedAnimation]. When the animation is /// 0, the destination is unselected, when the animation is 1, the destination /// is selected. /// @@ -1224,7 +1224,7 @@ class _NavigationBarDefaultsM2 extends NavigationBarThemeData { @override Color? get indicatorColor => _colors.secondary.withOpacity(0.24); - @override MaterialStateProperty? get labelTextStyle => MaterialStatePropertyAll(_theme.textTheme.overline!.copyWith(color: _colors.onSurface)); + @override MaterialStateProperty? get labelTextStyle => MaterialStatePropertyAll(_theme.textTheme.labelSmall!.copyWith(color: _colors.onSurface)); } // BEGIN GENERATED TOKEN PROPERTIES - NavigationBar diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 8502a119b2999..f3c2a10c09379 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -226,7 +226,7 @@ class NavigationRail extends StatefulWidget { /// When one of the [destinations] is selected the [selectedLabelTextStyle] /// will be used instead. /// - /// The default value is based on the [Theme]'s [TextTheme.bodyText1]. The + /// The default value is based on the [Theme]'s [TextTheme.bodyLarge]. The /// default color is based on the [Theme]'s [ColorScheme.onSurface]. /// /// Properties from this text style, or @@ -239,7 +239,7 @@ class NavigationRail extends StatefulWidget { /// When a [NavigationRailDestination] is not selected, /// [unselectedLabelTextStyle] will be used. /// - /// The default value is based on the [TextTheme.bodyText1] of + /// The default value is based on the [TextTheme.bodyLarge] of /// [ThemeData.textTheme]. The default color is based on the [Theme]'s /// [ColorScheme.primary]. /// @@ -936,11 +936,11 @@ class _NavigationRailDefaultsM2 extends NavigationRailThemeData { @override Color? get backgroundColor => _colors.surface; @override TextStyle? get unselectedLabelTextStyle { - return _theme.textTheme.bodyText1!.copyWith(color: _colors.onSurface.withOpacity(0.64)); + return _theme.textTheme.bodyLarge!.copyWith(color: _colors.onSurface.withOpacity(0.64)); } @override TextStyle? get selectedLabelTextStyle { - return _theme.textTheme.bodyText1!.copyWith(color: _colors.primary); + return _theme.textTheme.bodyLarge!.copyWith(color: _colors.primary); } @override IconThemeData? get unselectedIconTheme { diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 5d95f6e117936..2342ca71e6bd4 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -30,7 +30,7 @@ import 'theme_data.dart'; /// elevation) [Material] widget. The label's [Text] and [Icon] /// widgets are displayed in the [style]'s /// [ButtonStyle.foregroundColor] and the outline's weight and color -/// are defined by [ButtonStyle.side]. The button reacts to touches +/// are defined by [ButtonStyle.side]. The button reacts to touches /// by filling with the [style]'s [ButtonStyle.overlayColor]. /// /// The outlined button's default style is defined by [defaultStyleOf]. @@ -42,7 +42,7 @@ import 'theme_data.dart'; /// /// Unlike [TextButton] or [ElevatedButton], outline buttons have a /// default [ButtonStyle.side] which defines the appearance of the -/// outline. Because the default `side` is non-null, it +/// outline. Because the default `side` is non-null, it /// unconditionally overrides the shape's [OutlinedBorder.side]. In /// other words, to specify an outlined button's shape _and_ the /// appearance of its outline, both the [ButtonStyle.shape] and @@ -59,8 +59,10 @@ import 'theme_data.dart'; /// /// See also: /// -/// * [ElevatedButton], a filled Material Design button with a shadow. -/// * [TextButton], a Material Design button without a shadow. +/// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [FilledButton], a filled button that doesn't elevate when pressed. +/// * [FilledButton.tonal], a filled button variant that uses a secondary fill color. +/// * [TextButton], a button with no outline or fill color. /// * /// * class OutlinedButton extends ButtonStyleButton { @@ -165,7 +167,7 @@ class OutlinedButton extends ButtonStyleButton { ) Color? primary, @Deprecated( - 'Use disabledForegroundColor and disabledForegroundColor instead. ' + 'Use disabledForegroundColor instead. ' 'This feature was deprecated after v3.1.0.' ) Color? onSurface, @@ -318,7 +320,7 @@ class OutlinedButton extends ButtonStyleButton { disabledBackgroundColor: Colors.transparent, shadowColor: theme.shadowColor, elevation: 0, - textStyle: theme.textTheme.button, + textStyle: theme.textTheme.labelLarge, padding: _scaledPadding(context), minimumSize: const Size(64, 36), maximumSize: Size.infinite, diff --git a/packages/flutter/lib/src/material/outlined_button_theme.dart b/packages/flutter/lib/src/material/outlined_button_theme.dart index 1d29b8622d6e7..d5ad99d396dce 100644 --- a/packages/flutter/lib/src/material/outlined_button_theme.dart +++ b/packages/flutter/lib/src/material/outlined_button_theme.dart @@ -16,7 +16,7 @@ import 'theme.dart'; /// overall [Theme]'s [ThemeData.outlinedButtonTheme]. /// /// The [style]'s properties override [OutlinedButton]'s default style, -/// i.e. the [ButtonStyle] returned by [OutlinedButton.defaultStyleOf]. Only +/// i.e. the [ButtonStyle] returned by [OutlinedButton.defaultStyleOf]. Only /// the style's non-null property values or resolved non-null /// [MaterialStateProperty] values are used. /// diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 86f86bf17ff4f..f7276c3cf3617 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -39,7 +39,7 @@ class MaterialPageRoute extends PageRoute with MaterialRouteTransitionMixi super.settings, this.maintainState = true, super.fullscreenDialog, - super.preferRasterization = true, + super.allowSnapshotting = true, }) : assert(builder != null), assert(maintainState != null), assert(fullscreenDialog != null) { @@ -158,7 +158,7 @@ class MaterialPage extends Page { required this.child, this.maintainState = true, this.fullscreenDialog = false, - this.preferRasterization = true, + this.allowSnapshotting = true, super.key, super.name, super.arguments, @@ -176,12 +176,12 @@ class MaterialPage extends Page { /// {@macro flutter.widgets.PageRoute.fullscreenDialog} final bool fullscreenDialog; - /// {@macro flutter.widgets.TransitionRoute.preferRasterization} - final bool preferRasterization; + /// {@macro flutter.widgets.TransitionRoute.allowSnapshotting} + final bool allowSnapshotting; @override Route createRoute(BuildContext context) { - return _PageBasedMaterialPageRoute(page: this, preferRasterization: preferRasterization); + return _PageBasedMaterialPageRoute(page: this, allowSnapshotting: allowSnapshotting); } } @@ -192,7 +192,7 @@ class MaterialPage extends Page { class _PageBasedMaterialPageRoute extends PageRoute with MaterialRouteTransitionMixin { _PageBasedMaterialPageRoute({ required MaterialPage page, - super.preferRasterization, + super.allowSnapshotting, }) : assert(page != null), super(settings: page) { assert(opaque); diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index 7731a3c95c73a..bcc201c469cc9 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -156,7 +156,7 @@ class _ZoomPageTransition extends StatelessWidget { const _ZoomPageTransition({ required this.animation, required this.secondaryAnimation, - required this.preferRasterization, + required this.allowSnapshotting, this.child, }) : assert(animation != null), assert(secondaryAnimation != null); @@ -194,13 +194,12 @@ class _ZoomPageTransition extends StatelessWidget { /// property when the [_ZoomPageTransition] is used as a page transition. final Animation secondaryAnimation; - /// Whether the [RasterWidget] based-rasterized strategy for the zoom page transition - /// will be used. + /// Whether the [SnapshotWidget] will be used. /// /// Notably, this improves performance by disabling animations on both the outgoing and /// incoming route. This also implies that ink-splashes or similar animations will /// not animate during the transition. - final bool preferRasterization; + final bool allowSnapshotting; /// The widget below this widget in the tree. /// @@ -219,7 +218,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomEnterTransition( animation: animation, - preferRasterization: preferRasterization, + allowSnapshotting: allowSnapshotting, child: child, ); }, @@ -230,7 +229,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomExitTransition( animation: animation, - preferRasterization: preferRasterization, + allowSnapshotting: allowSnapshotting, reverse: true, child: child, ); @@ -244,7 +243,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomEnterTransition( animation: animation, - preferRasterization: preferRasterization, + allowSnapshotting: allowSnapshotting, reverse: true, child: child, ); @@ -256,7 +255,7 @@ class _ZoomPageTransition extends StatelessWidget { ) { return _ZoomExitTransition( animation: animation, - preferRasterization: preferRasterization, + allowSnapshotting: allowSnapshotting, child: child, ); }, @@ -270,14 +269,14 @@ class _ZoomEnterTransition extends StatefulWidget { const _ZoomEnterTransition({ required this.animation, this.reverse = false, - required this.preferRasterization, + required this.allowSnapshotting, this.child, }) : assert(animation != null), assert(reverse != null); final Animation animation; final Widget? child; - final bool preferRasterization; + final bool allowSnapshotting; final bool reverse; @override @@ -285,10 +284,13 @@ class _ZoomEnterTransition extends StatefulWidget { } class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTransitionBase { - // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - bool get allowRasterization => !kIsWeb && widget.preferRasterization; + // See SnapshotWidget doc comment, this is disabled on web because the HTML backend doesn't + // support this functionality and the canvaskit backend uses a single thread for UI and raster + // work which diminishes the impact of this performance improvement. + @override + bool get useSnapshot => !kIsWeb && widget.allowSnapshotting; - late _ZoomEnterTransitionDelegate delegate; + late _ZoomEnterTransitionPainter delegate; static final Animatable _fadeInTransition = Tween( begin: 0.0, @@ -327,7 +329,7 @@ class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTr @override void initState() { _updateAnimations(); - delegate = _ZoomEnterTransitionDelegate( + delegate = _ZoomEnterTransitionPainter( reverse: widget.reverse, fade: fadeTransition, scale: scaleTransition, @@ -343,7 +345,7 @@ class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTr oldWidget.animation.removeStatusListener(onAnimationStatusChange); _updateAnimations(); delegate.dispose(); - delegate = _ZoomEnterTransitionDelegate( + delegate = _ZoomEnterTransitionPainter( reverse: widget.reverse, fade: fadeTransition, scale: scaleTransition, @@ -363,11 +365,10 @@ class _ZoomEnterTransitionState extends State<_ZoomEnterTransition> with _ZoomTr @override Widget build(BuildContext context) { - return RasterWidget( - delegate: delegate, + return SnapshotWidget( + painter: delegate, controller: controller, - fallback: delegate, - mode: allowRasterization ? RasterizeMode.enabled : RasterizeMode.fallback, + mode: SnapshotMode.permissive, child: widget.child, ); } @@ -377,13 +378,13 @@ class _ZoomExitTransition extends StatefulWidget { const _ZoomExitTransition({ required this.animation, this.reverse = false, - required this.preferRasterization, + required this.allowSnapshotting, this.child, }) : assert(animation != null), assert(reverse != null); final Animation animation; - final bool preferRasterization; + final bool allowSnapshotting; final bool reverse; final Widget? child; @@ -392,10 +393,13 @@ class _ZoomExitTransition extends StatefulWidget { } class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTransitionBase { - late _ZoomExitTransitionDelegate delegate; + late _ZoomExitTransitionPainter delegate; - // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - bool get allowRasterization => !kIsWeb && widget.preferRasterization; + // See SnapshotWidget doc comment, this is disabled on web because the HTML backend doesn't + // support this functionality and the canvaskit backend uses a single thread for UI and raster + // work which diminishes the impact of this performance improvement. + @override + bool get useSnapshot => !kIsWeb && widget.allowSnapshotting; static final Animatable _fadeOutTransition = Tween( begin: 1.0, @@ -428,10 +432,11 @@ class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTran @override void initState() { _updateAnimations(); - delegate = _ZoomExitTransitionDelegate( + delegate = _ZoomExitTransitionPainter( reverse: widget.reverse, fade: fadeTransition, scale: scaleTransition, + animation: widget.animation, ); super.initState(); } @@ -443,10 +448,11 @@ class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTran oldWidget.animation.removeStatusListener(onAnimationStatusChange); _updateAnimations(); delegate.dispose(); - delegate = _ZoomExitTransitionDelegate( + delegate = _ZoomExitTransitionPainter( reverse: widget.reverse, fade: fadeTransition, scale: scaleTransition, + animation: widget.animation, ); } super.didUpdateWidget(oldWidget); @@ -462,11 +468,10 @@ class _ZoomExitTransitionState extends State<_ZoomExitTransition> with _ZoomTran @override Widget build(BuildContext context) { - return RasterWidget( - delegate: delegate, + return SnapshotWidget( + painter: delegate, controller: controller, - fallback: delegate, - mode: allowRasterization ? RasterizeMode.enabled : RasterizeMode.fallback, + mode: SnapshotMode.permissive, child: widget.child, ); } @@ -602,7 +607,7 @@ class ZoomPageTransitionsBuilder extends PageTransitionsBuilder { return _ZoomPageTransition( animation: animation, secondaryAnimation: secondaryAnimation, - preferRasterization: route?.preferRasterization ?? true, + allowSnapshotting: route?.allowSnapshotting ?? true, child: child, ); } @@ -765,12 +770,14 @@ void _updateScaledTransform(Matrix4 transform, double scale, Size size) { } mixin _ZoomTransitionBase { + bool get useSnapshot; + // Don't rasterize if: // 1. Rasterization is disabled by the platform. // 2. The animation is paused/stopped. // 3. The values of the scale/fade transition do not // benefit from rasterization. - final RasterWidgetController controller = RasterWidgetController(); + final SnapshotController controller = SnapshotController(); late Animation fadeTransition; late Animation scaleTransition; @@ -779,9 +786,9 @@ mixin _ZoomTransitionBase { if ((scaleTransition.value == 1.0) && (fadeTransition.value == 0.0 || fadeTransition.value == 1.0)) { - controller.rasterize = false; + controller.allowSnapshotting = false; } else { - controller.rasterize = true; + controller.allowSnapshotting = useSnapshot; } } @@ -789,28 +796,33 @@ mixin _ZoomTransitionBase { switch (status) { case AnimationStatus.dismissed: case AnimationStatus.completed: - controller.rasterize = false; + controller.allowSnapshotting = false; break; case AnimationStatus.forward: case AnimationStatus.reverse: - controller.rasterize = true; + controller.allowSnapshotting = useSnapshot; break; } } } -class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements RasterWidgetFallbackDelegate { - _ZoomEnterTransitionDelegate({ +class _ZoomEnterTransitionPainter extends SnapshotPainter { + _ZoomEnterTransitionPainter({ required this.reverse, required this.scale, required this.fade, required this.animation, }) { animation.addListener(notifyListeners); + animation.addStatusListener(_onStatusChange); scale.addListener(notifyListeners); fade.addListener(notifyListeners); } + void _onStatusChange(_) { + notifyListeners(); + } + final bool reverse; final Animation animation; final Animation scale; @@ -845,7 +857,15 @@ class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements Raste } @override - void paintFallback(PaintingContext context, ui.Offset offset, Size size, PaintingContextCallback painter) { + void paint(PaintingContext context, ui.Offset offset, Size size, PaintingContextCallback painter) { + switch (animation.status) { + case AnimationStatus.completed: + case AnimationStatus.dismissed: + return painter(context, offset); + case AnimationStatus.forward: + case AnimationStatus.reverse: + } + _drawScrim(context, offset, size); _updateScaledTransform(_transform, scale.value, size); _transformHandler.layer = context.pushTransform(true, offset, _transform, (PaintingContext context, Offset offset) { @@ -854,7 +874,7 @@ class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements Raste } @override - void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { + void paintSnapshot(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { _drawScrim(context, offset, size); _drawImageScaledAndCentered(context, image, scale.value, fade.value, pixelRatio); } @@ -862,6 +882,7 @@ class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements Raste @override void dispose() { animation.removeListener(notifyListeners); + animation.removeStatusListener(_onStatusChange); scale.removeListener(notifyListeners); fade.removeListener(notifyListeners); _opacityHandle.layer = null; @@ -870,7 +891,7 @@ class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements Raste } @override - bool shouldRepaint(covariant _ZoomEnterTransitionDelegate oldDelegate) { + bool shouldRepaint(covariant _ZoomEnterTransitionPainter oldDelegate) { return oldDelegate.reverse != reverse || oldDelegate.animation.value != animation.value || oldDelegate.scale.value != scale.value @@ -878,30 +899,46 @@ class _ZoomEnterTransitionDelegate extends RasterWidgetDelegate implements Raste } } -class _ZoomExitTransitionDelegate extends RasterWidgetDelegate implements RasterWidgetFallbackDelegate { - _ZoomExitTransitionDelegate({ +class _ZoomExitTransitionPainter extends SnapshotPainter { + _ZoomExitTransitionPainter({ required this.reverse, required this.scale, required this.fade, + required this.animation, }) { scale.addListener(notifyListeners); fade.addListener(notifyListeners); + animation.addStatusListener(_onStatusChange); + } + + void _onStatusChange(_) { + notifyListeners(); } final bool reverse; final Animation scale; final Animation fade; + final Animation animation; final Matrix4 _transform = Matrix4.zero(); final LayerHandle _opacityHandle = LayerHandle(); final LayerHandle _transformHandler = LayerHandle(); @override - void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { + void paintSnapshot(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { _drawImageScaledAndCentered(context, image, scale.value, fade.value, pixelRatio); } @override - void paintFallback(PaintingContext context, ui.Offset offset, Size size, PaintingContextCallback painter) { + void paint(PaintingContext context, ui.Offset offset, Size size, PaintingContextCallback painter) { + switch (animation.status) { + case AnimationStatus.completed: + case AnimationStatus.dismissed: + return painter(context, offset); + case AnimationStatus.forward: + case AnimationStatus.reverse: + break; + } + _updateScaledTransform(_transform, scale.value, size); _transformHandler.layer = context.pushTransform(true, offset, _transform, (PaintingContext context, Offset offset) { _opacityHandle.layer = context.pushOpacity(offset, (fade.value * 255).round(), painter, oldLayer: _opacityHandle.layer); @@ -909,7 +946,7 @@ class _ZoomExitTransitionDelegate extends RasterWidgetDelegate implements Raster } @override - bool shouldRepaint(covariant _ZoomExitTransitionDelegate oldDelegate) { + bool shouldRepaint(covariant _ZoomExitTransitionPainter oldDelegate) { return oldDelegate.reverse != reverse || oldDelegate.fade.value != fade.value || oldDelegate.scale.value != scale.value; } @@ -919,6 +956,7 @@ class _ZoomExitTransitionDelegate extends RasterWidgetDelegate implements Raster _transformHandler.layer = null; scale.removeListener(notifyListeners); fade.removeListener(notifyListeners); + animation.removeStatusListener(_onStatusChange); super.dispose(); } } diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index 567afe26e9a39..64ba4aa859879 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -404,7 +404,7 @@ class PaginatedDataTableState extends State { } // FOOTER - final TextStyle? footerTextStyle = themeData.textTheme.caption; + final TextStyle? footerTextStyle = themeData.textTheme.bodySmall; final List footerWidgets = []; if (widget.onRowsPerPageChanged != null) { final List availableRowsPerPage = widget.availableRowsPerPage @@ -493,8 +493,8 @@ class PaginatedDataTableState extends State { // These typographic styles aren't quite the regular ones. We pick the closest ones from the regular // list and then tweak them appropriately. // See https://material.io/design/components/data-tables.html#tables-within-cards - style: _selectedRowCount > 0 ? themeData.textTheme.subtitle1!.copyWith(color: themeData.colorScheme.secondary) - : themeData.textTheme.headline6!.copyWith(fontWeight: FontWeight.w400), + style: _selectedRowCount > 0 ? themeData.textTheme.titleMedium!.copyWith(color: themeData.colorScheme.secondary) + : themeData.textTheme.titleLarge!.copyWith(fontWeight: FontWeight.w400), child: IconTheme.merge( data: const IconThemeData( opacity: 0.54, diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index ee73bb0327947..1518652b4d67b 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -38,14 +38,6 @@ const double _kMenuVerticalPadding = 8.0; const double _kMenuWidthStep = 56.0; const double _kMenuScreenPadding = 8.0; -/// Used to configure how the [PopupMenuButton] positions its popup menu. -enum PopupMenuPosition { - /// Menu is positioned over the anchor. - over, - /// Menu is positioned under the anchor. - under, -} - /// A base class for entries in a Material Design popup menu. /// /// The popup menu widget uses this interface to interact with the menu items. @@ -267,7 +259,7 @@ class PopupMenuItem extends PopupMenuEntry { /// The text style of the popup menu item. /// /// If this property is null, then [PopupMenuThemeData.textStyle] is used. - /// If [PopupMenuThemeData.textStyle] is also null, then [TextTheme.subtitle1] + /// If [PopupMenuThemeData.textStyle] is also null, then [TextTheme.titleMedium] /// of [ThemeData.textTheme] is used. final TextStyle? textStyle; @@ -344,7 +336,7 @@ class PopupMenuItemState> extends State { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); - TextStyle style = widget.textStyle ?? popupMenuTheme.textStyle ?? theme.textTheme.subtitle1!; + TextStyle style = widget.textStyle ?? popupMenuTheme.textStyle ?? theme.textTheme.titleMedium!; if (!widget.enabled) { style = style.copyWith(color: theme.disabledColor); @@ -1025,7 +1017,7 @@ class PopupMenuButton extends StatefulWidget { this.color, this.enableFeedback, this.constraints, - this.position = PopupMenuPosition.over, + this.position, this.clipBehavior = Clip.none, }) : assert(itemBuilder != null), assert(enabled != null), @@ -1157,9 +1149,11 @@ class PopupMenuButton extends StatefulWidget { /// [offset] is used to change the position of the popup menu relative to the /// position set by this parameter. /// - /// When not set, the position defaults to [PopupMenuPosition.over] which makes the - /// popup menu appear directly over the button that was used to create it. - final PopupMenuPosition position; + /// If this property is `null`, then [PopupMenuThemeData.position] is used. If + /// [PopupMenuThemeData.position] is also `null`, then the position defaults + /// to [PopupMenuPosition.over] which makes the popup menu appear directly + /// over the button that was used to create it. + final PopupMenuPosition? position; /// {@macro flutter.material.Material.clipBehavior} /// @@ -1189,8 +1183,9 @@ class PopupMenuButtonState extends State> { final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); final RenderBox button = context.findRenderObject()! as RenderBox; final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox; + final PopupMenuPosition popupMenuPosition = widget.position ?? popupMenuTheme.position ?? PopupMenuPosition.over; final Offset offset; - switch (widget.position) { + switch (popupMenuPosition) { case PopupMenuPosition.over: offset = widget.offset; break; diff --git a/packages/flutter/lib/src/material/popup_menu_theme.dart b/packages/flutter/lib/src/material/popup_menu_theme.dart index 4479def0dd5f2..3ace02516c4ef 100644 --- a/packages/flutter/lib/src/material/popup_menu_theme.dart +++ b/packages/flutter/lib/src/material/popup_menu_theme.dart @@ -13,6 +13,14 @@ import 'theme.dart'; // Examples can assume: // late BuildContext context; +/// Used to configure how the [PopupMenuButton] positions its popup menu. +enum PopupMenuPosition { + /// Menu is positioned over the anchor. + over, + /// Menu is positioned under the anchor. + under, +} + /// Defines the visual properties of the routes used to display popup menus /// as well as [PopupMenuItem] and [PopupMenuDivider] widgets. /// @@ -43,6 +51,7 @@ class PopupMenuThemeData with Diagnosticable { this.textStyle, this.enableFeedback, this.mouseCursor, + this.position, }); /// The background color of the popup menu. @@ -67,6 +76,12 @@ class PopupMenuThemeData with Diagnosticable { /// If specified, overrides the default value of [PopupMenuItem.mouseCursor]. final MaterialStateProperty? mouseCursor; + /// Whether the popup menu is positioned over or under the popup menu button. + /// + /// When not set, the position defaults to [PopupMenuPosition.over] which makes the + /// popup menu appear directly over the button that was used to create it. + final PopupMenuPosition? position; + /// Creates a copy of this object with the given fields replaced with the /// new values. PopupMenuThemeData copyWith({ @@ -76,6 +91,7 @@ class PopupMenuThemeData with Diagnosticable { TextStyle? textStyle, bool? enableFeedback, MaterialStateProperty? mouseCursor, + PopupMenuPosition? position, }) { return PopupMenuThemeData( color: color ?? this.color, @@ -84,6 +100,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle: textStyle ?? this.textStyle, enableFeedback: enableFeedback ?? this.enableFeedback, mouseCursor: mouseCursor ?? this.mouseCursor, + position: position ?? this.position, ); } @@ -104,6 +121,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t), enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback, mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, + position: t < 0.5 ? a?.position : b?.position, ); } @@ -115,6 +133,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle, enableFeedback, mouseCursor, + position, ); @override @@ -131,7 +150,8 @@ class PopupMenuThemeData with Diagnosticable { && other.shape == shape && other.textStyle == textStyle && other.enableFeedback == enableFeedback - && other.mouseCursor == mouseCursor; + && other.mouseCursor == mouseCursor + && other.position == position; } @override @@ -143,6 +163,7 @@ class PopupMenuThemeData with Diagnosticable { properties.add(DiagnosticsProperty('text style', textStyle, defaultValue: null)); properties.add(DiagnosticsProperty('enableFeedback', enableFeedback, defaultValue: null)); properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: null)); + properties.add(EnumProperty('position', position, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index df6839f3f457f..f9b62d8528a12 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -114,7 +114,7 @@ class RangeSlider extends StatefulWidget { /// the slider. To know when the value starts to change, or when it is done /// changing, set the optional callbacks [onChangeStart] and/or [onChangeEnd]. /// - /// * [values], which determines currently selected values for this range + /// * [values], which determines currently selected values for this range /// slider. /// * [onChanged], which is called while the user is selecting a new value for /// the range slider. @@ -190,7 +190,7 @@ class RangeSlider extends StatefulWidget { /// /// See also: /// - /// * [onChangeStart], which is called when the user starts changing the + /// * [onChangeStart], which is called when the user starts changing the /// values. /// * [onChangeEnd], which is called when the user stops changing the values. final ValueChanged? onChanged; @@ -292,7 +292,7 @@ class RangeSlider extends StatefulWidget { /// There are two labels: one for the start thumb and one for the end thumb. /// /// Each label is rendered using the active [ThemeData]'s - /// [TextTheme.bodyText1] text style, with the theme data's + /// [TextTheme.bodyLarge] text style, with the theme data's /// [ColorScheme.onPrimary] color. The label's text style can be overridden /// with [SliderThemeData.valueIndicatorTextStyle]. /// @@ -609,7 +609,7 @@ class _RangeSliderState extends State with TickerProviderStateMixin overlayShape: sliderTheme.overlayShape ?? defaultOverlayShape, rangeValueIndicatorShape: valueIndicatorShape, showValueIndicator: sliderTheme.showValueIndicator ?? defaultShowValueIndicator, - valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyText1!.copyWith( + valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyLarge!.copyWith( color: theme.colorScheme.onPrimary, ), minThumbSeparation: sliderTheme.minThumbSeparation ?? defaultMinThumbSeparation, @@ -655,7 +655,7 @@ class _RangeSliderState extends State with TickerProviderStateMixin ); }, ); - Overlay.of(context, debugRequiredFor: widget)!.insert(overlayEntry!); + Overlay.of(context, debugRequiredFor: widget).insert(overlayEntry!); } } } diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 23d753c899dac..ed45fb74b6137 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1305,15 +1305,15 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr @override void didUpdateWidget(_FloatingActionButtonTransition oldWidget) { super.didUpdateWidget(oldWidget); + if (oldWidget.fabMotionAnimator != widget.fabMotionAnimator || oldWidget.fabMoveAnimation != widget.fabMoveAnimation) { + // Get the right scale and rotation animations to use for this widget. + _updateAnimations(); + } final bool oldChildIsNull = oldWidget.child == null; final bool newChildIsNull = widget.child == null; if (oldChildIsNull == newChildIsNull && oldWidget.child?.key == widget.child?.key) { return; } - if (oldWidget.fabMotionAnimator != widget.fabMotionAnimator || oldWidget.fabMoveAnimation != widget.fabMoveAnimation) { - // Get the right scale and rotation animations to use for this widget. - _updateAnimations(); - } if (_previousController.status == AnimationStatus.dismissed) { final double currentValue = widget.currentController.value; if (currentValue == 0.0 || oldWidget.child == null) { @@ -2484,7 +2484,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto double get _floatingActionButtonVisibilityValue => _floatingActionButtonVisibilityController.value; /// Sets the current value of the visibility animation for the - /// [Scaffold.floatingActionButton]. This value must not be null. + /// [Scaffold.floatingActionButton]. This value must not be null. set _floatingActionButtonVisibilityValue(double newValue) { assert(newValue != null); _floatingActionButtonVisibilityController.value = clampDouble(newValue, @@ -2522,7 +2522,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto // iOS FEATURES - status bar tap, back gesture // On iOS, tapping the status bar scrolls the app's primary scrollable to the - // top. We implement this by looking up the primary scroll controller and + // top. We implement this by looking up the primary scroll controller and // scrolling it to the top when tapped. void _handleStatusBarTap() { final ScrollController? primaryScrollController = PrimaryScrollController.of(context); diff --git a/packages/flutter/lib/src/material/search.dart b/packages/flutter/lib/src/material/search.dart index 04b730d06777f..0f1cbaf234911 100644 --- a/packages/flutter/lib/src/material/search.dart +++ b/packages/flutter/lib/src/material/search.dart @@ -583,7 +583,7 @@ class _SearchPageState extends State<_SearchPage> { title: TextField( controller: widget.delegate._queryTextController, focusNode: focusNode, - style: widget.delegate.searchFieldStyle ?? theme.textTheme.headline6, + style: widget.delegate.searchFieldStyle ?? theme.textTheme.titleLarge, textInputAction: widget.delegate.textInputAction, keyboardType: widget.delegate.keyboardType, onSubmitted: (String _) { diff --git a/packages/flutter/lib/src/material/selection_area.dart b/packages/flutter/lib/src/material/selection_area.dart index 49f98ef748271..7c5daafb863a3 100644 --- a/packages/flutter/lib/src/material/selection_area.dart +++ b/packages/flutter/lib/src/material/selection_area.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/cupertino.dart'; +import 'package:flutter/rendering.dart'; import 'debug.dart'; import 'desktop_text_selection.dart'; @@ -41,6 +42,7 @@ class SelectionArea extends StatefulWidget { this.focusNode, this.selectionControls, this.magnifierConfiguration, + this.onSelectionChanged, required this.child, }); @@ -63,6 +65,9 @@ class SelectionArea extends StatefulWidget { /// If it is null, the platform specific selection control is used. final TextSelectionControls? selectionControls; + /// Called when the selected content changes. + final ValueChanged? onSelectionChanged; + /// The child widget this selection area applies to. /// /// {@macro flutter.widgets.ProxyWidget.child} @@ -112,6 +117,7 @@ class _SelectionAreaState extends State { focusNode: _effectiveFocusNode, selectionControls: controls, magnifierConfiguration: widget.magnifierConfiguration ?? TextMagnifier.adaptiveMagnifierConfiguration, + onSelectionChanged: widget.onSelectionChanged, child: widget.child, ); } diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 04c761b0b6a4c..8ed0c0ee19f31 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -48,6 +48,13 @@ enum _SliderType { material, adaptive } /// ** See code in examples/api/lib/material/slider/slider.0.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example shows a [Slider] widget using the [Slider.secondaryTrackValue] +/// to show a secondary track in the slider. +/// +/// ** See code in examples/api/lib/material/slider/slider.1.dart ** +/// {@end-tool} +/// /// A slider can be used to select from either a continuous or a discrete set of /// values. The default is to use a continuous range of values from [min] to /// [max]. To use discrete values, use a non-null value for [divisions], which @@ -125,6 +132,7 @@ class Slider extends StatefulWidget { const Slider({ super.key, required this.value, + this.secondaryTrackValue, required this.onChanged, this.onChangeStart, this.onChangeEnd, @@ -134,6 +142,7 @@ class Slider extends StatefulWidget { this.label, this.activeColor, this.inactiveColor, + this.secondaryActiveColor, this.thumbColor, this.mouseCursor, this.semanticFormatterCallback, @@ -146,6 +155,8 @@ class Slider extends StatefulWidget { assert(min <= max), assert(value >= min && value <= max, 'Value $value is not between minimum $min and maximum $max'), + assert(secondaryTrackValue == null || (secondaryTrackValue >= min && secondaryTrackValue <= max), + 'SecondaryValue $secondaryTrackValue is not between $min and $max'), assert(divisions == null || divisions > 0); /// Creates an adaptive [Slider] based on the target platform, following @@ -155,13 +166,15 @@ class Slider extends StatefulWidget { /// Creates a [CupertinoSlider] if the target platform is iOS or macOS, creates a /// Material Design slider otherwise. /// - /// If a [CupertinoSlider] is created, the following parameters are - /// ignored: [label], [inactiveColor], [semanticFormatterCallback]. + /// If a [CupertinoSlider] is created, the following parameters are ignored: + /// [secondaryTrackValue], [label], [inactiveColor], [secondaryActiveColor], + /// [semanticFormatterCallback]. /// /// The target platform is based on the current [Theme]: [ThemeData.platform]. const Slider.adaptive({ super.key, required this.value, + this.secondaryTrackValue, required this.onChanged, this.onChangeStart, this.onChangeEnd, @@ -172,6 +185,7 @@ class Slider extends StatefulWidget { this.mouseCursor, this.activeColor, this.inactiveColor, + this.secondaryActiveColor, this.thumbColor, this.semanticFormatterCallback, this.focusNode, @@ -181,7 +195,10 @@ class Slider extends StatefulWidget { assert(min != null), assert(max != null), assert(min <= max), - assert(value >= min && value <= max), + assert(value >= min && value <= max, + 'Value $value is not between minimum $min and maximum $max'), + assert(secondaryTrackValue == null || (secondaryTrackValue >= min && secondaryTrackValue <= max), + 'SecondaryValue $secondaryTrackValue is not between $min and $max'), assert(divisions == null || divisions > 0); /// The currently selected value for this slider. @@ -189,6 +206,17 @@ class Slider extends StatefulWidget { /// The slider's thumb is drawn at a position that corresponds to this value. final double value; + /// The secondary track value for this slider. + /// + /// If not null, a secondary track using [Slider.secondaryActiveColor] color + /// is drawn between the thumb and this value, over the inactive track. + /// + /// If less than [Slider.value], then the secondary track is not shown. + /// + /// It can be ideal for media scenarios such as showing the buffering progress + /// while the [Slider.value] shows the play progress. + final double? secondaryTrackValue; + /// Called during a drag when the user is selecting a new value for the slider /// by dragging. /// @@ -324,7 +352,7 @@ class Slider extends StatefulWidget { /// It is used to display the value of a discrete slider, and it is displayed /// as part of the value indicator shape. /// - /// The label is rendered using the active [ThemeData]'s [TextTheme.bodyText1] + /// The label is rendered using the active [ThemeData]'s [TextTheme.bodyLarge] /// text style, with the theme data's [ColorScheme.onPrimary] color. The /// label's text style can be overridden with /// [SliderThemeData.valueIndicatorTextStyle]. @@ -365,6 +393,18 @@ class Slider extends StatefulWidget { /// Ignored if this slider is created with [Slider.adaptive]. final Color? inactiveColor; + /// The color to use for the portion of the slider track between the thumb and + /// the [Slider.secondaryTrackValue]. + /// + /// Defaults to the [SliderThemeData.secondaryActiveTrackColor] of the current + /// [SliderTheme]. + /// + /// Using a [SliderTheme] gives much more fine-grained control over the + /// appearance of various components of the slider. + /// + /// Ignored if this slider is created with [Slider.adaptive]. + final Color? secondaryActiveColor; + /// The color of the thumb. /// /// If this color is null: @@ -443,6 +483,7 @@ class Slider extends StatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DoubleProperty('value', value)); + properties.add(DoubleProperty('secondaryTrackValue', secondaryTrackValue)); properties.add(ObjectFlagProperty>('onChanged', onChanged, ifNull: 'disabled')); properties.add(ObjectFlagProperty>.has('onChangeStart', onChangeStart)); properties.add(ObjectFlagProperty>.has('onChangeEnd', onChangeEnd)); @@ -452,6 +493,7 @@ class Slider extends StatefulWidget { properties.add(StringProperty('label', label)); properties.add(ColorProperty('activeColor', activeColor)); properties.add(ColorProperty('inactiveColor', inactiveColor)); + properties.add(ColorProperty('secondaryActiveColor', secondaryActiveColor)); properties.add(ObjectFlagProperty>.has('semanticFormatterCallback', semanticFormatterCallback)); properties.add(ObjectFlagProperty.has('focusNode', focusNode)); properties.add(FlagProperty('autofocus', value: autofocus, ifTrue: 'autofocus')); @@ -708,8 +750,10 @@ class _SliderState extends State with TickerProviderStateMixin { trackHeight: sliderTheme.trackHeight ?? defaultTrackHeight, activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary, inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.24), + secondaryActiveTrackColor: widget.secondaryActiveColor ?? sliderTheme.secondaryActiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.54), disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.32), disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12), + disabledSecondaryActiveTrackColor: sliderTheme.disabledSecondaryActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12), activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.54), inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? theme.colorScheme.primary.withOpacity(0.54), disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.12), @@ -724,7 +768,7 @@ class _SliderState extends State with TickerProviderStateMixin { overlayShape: sliderTheme.overlayShape ?? defaultOverlayShape, valueIndicatorShape: valueIndicatorShape, showValueIndicator: sliderTheme.showValueIndicator ?? defaultShowValueIndicator, - valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyText1!.copyWith( + valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.bodyLarge!.copyWith( color: theme.colorScheme.onPrimary, ), ); @@ -789,6 +833,7 @@ class _SliderState extends State with TickerProviderStateMixin { child: _SliderRenderObjectWidget( key: _renderObjectKey, value: _convert(widget.value), + secondaryTrackValue: (widget.secondaryTrackValue != null) ? _convert(widget.secondaryTrackValue!) : null, divisions: widget.divisions, label: widget.label, sliderTheme: sliderTheme, @@ -842,7 +887,7 @@ class _SliderState extends State with TickerProviderStateMixin { ); }, ); - Overlay.of(context, debugRequiredFor: widget)!.insert(overlayEntry!); + Overlay.of(context, debugRequiredFor: widget).insert(overlayEntry!); } } } @@ -852,6 +897,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { const _SliderRenderObjectWidget({ super.key, required this.value, + required this.secondaryTrackValue, required this.divisions, required this.label, required this.sliderTheme, @@ -867,6 +913,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { }); final double value; + final double? secondaryTrackValue; final int? divisions; final String? label; final SliderThemeData sliderTheme; @@ -884,6 +931,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { _RenderSlider createRenderObject(BuildContext context) { return _RenderSlider( value: value, + secondaryTrackValue: secondaryTrackValue, divisions: divisions, label: label, sliderTheme: sliderTheme, @@ -909,6 +957,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { // setter dependent on the `divisions`. ..divisions = divisions ..value = value + ..secondaryTrackValue = secondaryTrackValue ..label = label ..sliderTheme = sliderTheme ..textScaleFactor = textScaleFactor @@ -930,6 +979,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { _RenderSlider({ required double value, + required double? secondaryTrackValue, required int? divisions, required String? label, required SliderThemeData sliderTheme, @@ -946,12 +996,14 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { required bool hovering, required DeviceGestureSettings gestureSettings, }) : assert(value != null && value >= 0.0 && value <= 1.0), + assert(secondaryTrackValue == null || (secondaryTrackValue >= 0.0 && secondaryTrackValue <= 1.0)), assert(state != null), assert(textDirection != null), _platform = platform, _semanticFormatterCallback = semanticFormatterCallback, _label = label, _value = value, + _secondaryTrackValue = secondaryTrackValue, _divisions = divisions, _sliderTheme = sliderTheme, _textScaleFactor = textScaleFactor, @@ -1059,6 +1111,17 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { markNeedsSemanticsUpdate(); } + double? get secondaryTrackValue => _secondaryTrackValue; + double? _secondaryTrackValue; + set secondaryTrackValue(double? newValue) { + assert(newValue == null || (newValue >= 0.0 && newValue <= 1.0)); + if (newValue == _secondaryTrackValue) { + return; + } + _secondaryTrackValue = newValue; + markNeedsSemanticsUpdate(); + } + DeviceGestureSettings? get gestureSettings => _drag.gestureSettings; set gestureSettings(DeviceGestureSettings? gestureSettings) { _drag.gestureSettings = gestureSettings; @@ -1417,17 +1480,21 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { @override void paint(PaintingContext context, Offset offset) { final double value = _state.positionController.value; + final double? secondaryValue = _secondaryTrackValue; // The visual position is the position of the thumb from 0 to 1 from left // to right. In left to right, this is the same as the value, but it is // reversed for right to left text. final double visualPosition; + final double? secondaryVisualPosition; switch (textDirection) { case TextDirection.rtl: visualPosition = 1.0 - value; + secondaryVisualPosition = (secondaryValue != null) ? (1.0 - secondaryValue) : null; break; case TextDirection.ltr: visualPosition = value; + secondaryVisualPosition = (secondaryValue != null) ? secondaryValue : null; break; } @@ -1438,6 +1505,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { isDiscrete: isDiscrete, ); final Offset thumbCenter = Offset(trackRect.left + visualPosition * trackRect.width, trackRect.center.dy); + final Offset? secondaryOffset = (secondaryVisualPosition != null) ? Offset(trackRect.left + secondaryVisualPosition * trackRect.width, trackRect.center.dy) : null; _sliderTheme.trackShape!.paint( context, @@ -1447,6 +1515,7 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { enableAnimation: _enableAnimation, textDirection: _textDirection, thumbCenter: thumbCenter, + secondaryOffset: secondaryOffset, isDiscrete: isDiscrete, isEnabled: isInteractive, ); diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index eeed8a2808132..c53662e1cfcb2 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -266,8 +266,10 @@ class SliderThemeData with Diagnosticable { this.trackHeight, this.activeTrackColor, this.inactiveTrackColor, + this.secondaryActiveTrackColor, this.disabledActiveTrackColor, this.disabledInactiveTrackColor, + this.disabledSecondaryActiveTrackColor, this.activeTickMarkColor, this.inactiveTickMarkColor, this.disabledActiveTickMarkColor, @@ -317,8 +319,10 @@ class SliderThemeData with Diagnosticable { // component Colors (with opacity) from base colors. const int activeTrackAlpha = 0xff; const int inactiveTrackAlpha = 0x3d; // 24% opacity + const int secondaryActiveTrackAlpha = 0x8a; // 54% opacity const int disabledActiveTrackAlpha = 0x52; // 32% opacity const int disabledInactiveTrackAlpha = 0x1f; // 12% opacity + const int disabledSecondaryActiveTrackAlpha = 0x1f; // 12% opacity const int activeTickMarkAlpha = 0x8a; // 54% opacity const int inactiveTickMarkAlpha = 0x8a; // 54% opacity const int disabledActiveTickMarkAlpha = 0x1f; // 12% opacity @@ -332,8 +336,10 @@ class SliderThemeData with Diagnosticable { trackHeight: 2.0, activeTrackColor: primaryColor.withAlpha(activeTrackAlpha), inactiveTrackColor: primaryColor.withAlpha(inactiveTrackAlpha), + secondaryActiveTrackColor: primaryColor.withAlpha(secondaryActiveTrackAlpha), disabledActiveTrackColor: primaryColorDark.withAlpha(disabledActiveTrackAlpha), disabledInactiveTrackColor: primaryColorDark.withAlpha(disabledInactiveTrackAlpha), + disabledSecondaryActiveTrackColor: primaryColorDark.withAlpha(disabledSecondaryActiveTrackAlpha), activeTickMarkColor: primaryColorLight.withAlpha(activeTickMarkAlpha), inactiveTickMarkColor: primaryColor.withAlpha(inactiveTickMarkAlpha), disabledActiveTickMarkColor: primaryColorLight.withAlpha(disabledActiveTickMarkAlpha), @@ -368,10 +374,18 @@ class SliderThemeData with Diagnosticable { /// [Slider.max] position. final Color? inactiveTrackColor; + /// The color of the [Slider] track between the current thumb position and the + /// [Slider.secondaryTrackValue] position. + final Color? secondaryActiveTrackColor; + /// The color of the [Slider] track between the [Slider.min] position and the /// current thumb position when the [Slider] is disabled. final Color? disabledActiveTrackColor; + /// The color of the [Slider] track between the current thumb position and the + /// [Slider.secondaryTrackValue] position when the [Slider] is disabled. + final Color? disabledSecondaryActiveTrackColor; + /// The color of the [Slider] track between the current thumb position and the /// [Slider.max] position when the [Slider] is disabled. final Color? disabledInactiveTrackColor; @@ -573,8 +587,10 @@ class SliderThemeData with Diagnosticable { double? trackHeight, Color? activeTrackColor, Color? inactiveTrackColor, + Color? secondaryActiveTrackColor, Color? disabledActiveTrackColor, Color? disabledInactiveTrackColor, + Color? disabledSecondaryActiveTrackColor, Color? activeTickMarkColor, Color? inactiveTickMarkColor, Color? disabledActiveTickMarkColor, @@ -603,8 +619,10 @@ class SliderThemeData with Diagnosticable { trackHeight: trackHeight ?? this.trackHeight, activeTrackColor: activeTrackColor ?? this.activeTrackColor, inactiveTrackColor: inactiveTrackColor ?? this.inactiveTrackColor, + secondaryActiveTrackColor: secondaryActiveTrackColor ?? this.secondaryActiveTrackColor, disabledActiveTrackColor: disabledActiveTrackColor ?? this.disabledActiveTrackColor, disabledInactiveTrackColor: disabledInactiveTrackColor ?? this.disabledInactiveTrackColor, + disabledSecondaryActiveTrackColor: disabledSecondaryActiveTrackColor ?? this.disabledSecondaryActiveTrackColor, activeTickMarkColor: activeTickMarkColor ?? this.activeTickMarkColor, inactiveTickMarkColor: inactiveTickMarkColor ?? this.inactiveTickMarkColor, disabledActiveTickMarkColor: disabledActiveTickMarkColor ?? this.disabledActiveTickMarkColor, @@ -644,8 +662,10 @@ class SliderThemeData with Diagnosticable { trackHeight: lerpDouble(a.trackHeight, b.trackHeight, t), activeTrackColor: Color.lerp(a.activeTrackColor, b.activeTrackColor, t), inactiveTrackColor: Color.lerp(a.inactiveTrackColor, b.inactiveTrackColor, t), + secondaryActiveTrackColor: Color.lerp(a.secondaryActiveTrackColor, b.secondaryActiveTrackColor, t), disabledActiveTrackColor: Color.lerp(a.disabledActiveTrackColor, b.disabledActiveTrackColor, t), disabledInactiveTrackColor: Color.lerp(a.disabledInactiveTrackColor, b.disabledInactiveTrackColor, t), + disabledSecondaryActiveTrackColor: Color.lerp(a.disabledSecondaryActiveTrackColor, b.disabledSecondaryActiveTrackColor, t), activeTickMarkColor: Color.lerp(a.activeTickMarkColor, b.activeTickMarkColor, t), inactiveTickMarkColor: Color.lerp(a.inactiveTickMarkColor, b.inactiveTickMarkColor, t), disabledActiveTickMarkColor: Color.lerp(a.disabledActiveTickMarkColor, b.disabledActiveTickMarkColor, t), @@ -677,8 +697,10 @@ class SliderThemeData with Diagnosticable { trackHeight, activeTrackColor, inactiveTrackColor, + secondaryActiveTrackColor, disabledActiveTrackColor, disabledInactiveTrackColor, + disabledSecondaryActiveTrackColor, activeTickMarkColor, inactiveTickMarkColor, disabledActiveTickMarkColor, @@ -691,9 +713,9 @@ class SliderThemeData with Diagnosticable { overlayShape, tickMarkShape, thumbShape, - trackShape, - valueIndicatorShape, Object.hash( + trackShape, + valueIndicatorShape, rangeTickMarkShape, rangeThumbShape, rangeTrackShape, @@ -718,8 +740,10 @@ class SliderThemeData with Diagnosticable { && other.trackHeight == trackHeight && other.activeTrackColor == activeTrackColor && other.inactiveTrackColor == inactiveTrackColor + && other.secondaryActiveTrackColor == secondaryActiveTrackColor && other.disabledActiveTrackColor == disabledActiveTrackColor && other.disabledInactiveTrackColor == disabledInactiveTrackColor + && other.disabledSecondaryActiveTrackColor == disabledSecondaryActiveTrackColor && other.activeTickMarkColor == activeTickMarkColor && other.inactiveTickMarkColor == inactiveTickMarkColor && other.disabledActiveTickMarkColor == disabledActiveTickMarkColor @@ -752,8 +776,10 @@ class SliderThemeData with Diagnosticable { properties.add(DoubleProperty('trackHeight', trackHeight, defaultValue: defaultData.trackHeight)); properties.add(ColorProperty('activeTrackColor', activeTrackColor, defaultValue: defaultData.activeTrackColor)); properties.add(ColorProperty('inactiveTrackColor', inactiveTrackColor, defaultValue: defaultData.inactiveTrackColor)); + properties.add(ColorProperty('secondaryActiveTrackColor', secondaryActiveTrackColor, defaultValue: defaultData.secondaryActiveTrackColor)); properties.add(ColorProperty('disabledActiveTrackColor', disabledActiveTrackColor, defaultValue: defaultData.disabledActiveTrackColor)); properties.add(ColorProperty('disabledInactiveTrackColor', disabledInactiveTrackColor, defaultValue: defaultData.disabledInactiveTrackColor)); + properties.add(ColorProperty('disabledSecondaryActiveTrackColor', disabledSecondaryActiveTrackColor, defaultValue: defaultData.disabledSecondaryActiveTrackColor)); properties.add(ColorProperty('activeTickMarkColor', activeTickMarkColor, defaultValue: defaultData.activeTickMarkColor)); properties.add(ColorProperty('inactiveTickMarkColor', inactiveTickMarkColor, defaultValue: defaultData.inactiveTickMarkColor)); properties.add(ColorProperty('disabledActiveTickMarkColor', disabledActiveTickMarkColor, defaultValue: defaultData.disabledActiveTickMarkColor)); @@ -1047,6 +1073,11 @@ abstract class SliderTrackShape { /// relative to the origin of the [PaintingContext.canvas]. It can be used as /// the point that divides the track into 2 segments. /// + /// The `secondaryOffset` argument is the offset of the secondary value + /// relative to the origin of the [PaintingContext.canvas]. + /// + /// If not null, the track is divided into 3 segments. + /// /// {@macro flutter.material.SliderTickMarkShape.getPreferredSize.isEnabled} /// /// {@macro flutter.material.SliderComponentShape.paint.isDiscrete} @@ -1068,6 +1099,7 @@ abstract class SliderTrackShape { required SliderThemeData sliderTheme, required Animation enableAnimation, required Offset thumbCenter, + Offset? secondaryOffset, bool isEnabled, bool isDiscrete, required TextDirection textDirection, @@ -1464,7 +1496,7 @@ mixin BaseSliderTrackShape { /// [Slider]. /// /// The width is the width of the [Slider] or [RangeSlider], but padded by - /// the max of the overlay and thumb radius. The height is defined by the + /// the max of the overlay and thumb radius. The height is defined by the /// [SliderThemeData.trackHeight]. /// /// The [Rect] is centered both horizontally and vertically within the slider @@ -1534,6 +1566,7 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS required Animation enableAnimation, required TextDirection textDirection, required Offset thumbCenter, + Offset? secondaryOffset, bool isDiscrete = false, bool isEnabled = false, }) { @@ -1593,6 +1626,25 @@ class RectangularSliderTrackShape extends SliderTrackShape with BaseSliderTrackS if (!rightTrackSegment.isEmpty) { context.canvas.drawRect(rightTrackSegment, rightTrackPaint); } + + final bool showSecondaryTrack = (secondaryOffset != null) && + ((textDirection == TextDirection.ltr) + ? (secondaryOffset.dx > thumbCenter.dx) + : (secondaryOffset.dx < thumbCenter.dx)); + + if (showSecondaryTrack) { + final ColorTween secondaryTrackColorTween = ColorTween(begin: sliderTheme.disabledSecondaryActiveTrackColor, end: sliderTheme.secondaryActiveTrackColor); + final Paint secondaryTrackPaint = Paint()..color = secondaryTrackColorTween.evaluate(enableAnimation)!; + final Rect secondaryTrackSegment = Rect.fromLTRB( + (textDirection == TextDirection.ltr) ? thumbCenter.dx : secondaryOffset.dx, + trackRect.top, + (textDirection == TextDirection.ltr) ? secondaryOffset.dx : thumbCenter.dx, + trackRect.bottom, + ); + if (!secondaryTrackSegment.isEmpty) { + context.canvas.drawRect(secondaryTrackSegment, secondaryTrackPaint); + } + } } } @@ -1635,6 +1687,7 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS required Animation enableAnimation, required TextDirection textDirection, required Offset thumbCenter, + Offset? secondaryOffset, bool isDiscrete = false, bool isEnabled = false, double additionalActiveTrackHeight = 2, @@ -1653,7 +1706,7 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS assert(thumbCenter != null); // If the slider [SliderThemeData.trackHeight] is less than or equal to 0, // then it makes no difference whether the track is painted or not, - // therefore the painting can be a no-op. + // therefore the painting can be a no-op. if (sliderTheme.trackHeight == null || sliderTheme.trackHeight! <= 0) { return; } @@ -1709,6 +1762,41 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS ), rightTrackPaint, ); + + final bool showSecondaryTrack = (secondaryOffset != null) && + ((textDirection == TextDirection.ltr) + ? (secondaryOffset.dx > thumbCenter.dx) + : (secondaryOffset.dx < thumbCenter.dx)); + + if (showSecondaryTrack) { + final ColorTween secondaryTrackColorTween = ColorTween(begin: sliderTheme.disabledSecondaryActiveTrackColor, end: sliderTheme.secondaryActiveTrackColor); + final Paint secondaryTrackPaint = Paint()..color = secondaryTrackColorTween.evaluate(enableAnimation)!; + if (textDirection == TextDirection.ltr) { + context.canvas.drawRRect( + RRect.fromLTRBAndCorners( + thumbCenter.dx, + trackRect.top, + secondaryOffset.dx, + trackRect.bottom, + topRight: trackRadius, + bottomRight: trackRadius, + ), + secondaryTrackPaint, + ); + } else { + context.canvas.drawRRect( + RRect.fromLTRBAndCorners( + secondaryOffset.dx, + trackRect.top, + thumbCenter.dx, + trackRect.bottom, + topLeft: trackRadius, + bottomLeft: trackRadius, + ), + secondaryTrackPaint, + ); + } + } } } @@ -2243,7 +2331,7 @@ class _EmptySliderTickMarkShape extends SliderTickMarkShape { /// that will not paint any component shape. A static reference is stored in /// [SliderTickMarkShape.noThumb] and [SliderTickMarkShape.noOverlay]. When this value /// is specified for [SliderThemeData.thumbShape], the thumb painting is -/// skipped. When this value is specified for [SliderThemeData.overlayShape], +/// skipped. When this value is specified for [SliderThemeData.overlayShape], /// the overlay painting is skipped. class _EmptySliderComponentShape extends SliderComponentShape { @override @@ -3173,7 +3261,7 @@ class _PaddleSliderValueIndicatorPathPainter { 0, ); - // This is the needed extra width for the label. It is only positive when + // This is the needed extra width for the label. It is only positive when // the label exceeds the minimum size contained by the round top lobe. final double halfWidthNeeded = math.max( 0.0, diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 20fb61cee9f28..d4a23825c0fa0 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -468,7 +468,7 @@ class _SnackBarState extends State { ), ); - final TextStyle? contentTextStyle = snackBarTheme.contentTextStyle ?? ThemeData(brightness: brightness).textTheme.subtitle1; + final TextStyle? contentTextStyle = snackBarTheme.contentTextStyle ?? ThemeData(brightness: brightness).textTheme.titleMedium; final SnackBarBehavior snackBarBehavior = widget.behavior ?? snackBarTheme.behavior ?? SnackBarBehavior.fixed; assert((){ // Whether the behavior is set through the constructor or the theme, diff --git a/packages/flutter/lib/src/material/stepper.dart b/packages/flutter/lib/src/material/stepper.dart index a3fe58b535ed7..13d0b3fdd8869 100644 --- a/packages/flutter/lib/src/material/stepper.dart +++ b/packages/flutter/lib/src/material/stepper.dart @@ -165,7 +165,7 @@ class Step { final bool isActive; /// Only [StepperType.horizontal], Optional widget that appears under the [title]. - /// By default, uses the `bodyText1` theme. + /// By default, uses the `bodyLarge` theme. final Widget? label; } @@ -554,13 +554,13 @@ class _StepperState extends State with TickerProviderStateMixin { case StepState.indexed: case StepState.editing: case StepState.complete: - return textTheme.bodyText1!; + return textTheme.bodyLarge!; case StepState.disabled: - return textTheme.bodyText1!.copyWith( + return textTheme.bodyLarge!.copyWith( color: _isDark() ? _kDisabledDark : _kDisabledLight, ); case StepState.error: - return textTheme.bodyText1!.copyWith( + return textTheme.bodyLarge!.copyWith( color: _isDark() ? _kErrorDark : _kErrorLight, ); } @@ -575,13 +575,13 @@ class _StepperState extends State with TickerProviderStateMixin { case StepState.indexed: case StepState.editing: case StepState.complete: - return textTheme.caption!; + return textTheme.bodySmall!; case StepState.disabled: - return textTheme.caption!.copyWith( + return textTheme.bodySmall!.copyWith( color: _isDark() ? _kDisabledDark : _kDisabledLight, ); case StepState.error: - return textTheme.caption!.copyWith( + return textTheme.bodySmall!.copyWith( color: _isDark() ? _kErrorDark : _kErrorLight, ); } @@ -596,13 +596,13 @@ class _StepperState extends State with TickerProviderStateMixin { case StepState.indexed: case StepState.editing: case StepState.complete: - return textTheme.bodyText1!; + return textTheme.bodyLarge!; case StepState.disabled: - return textTheme.bodyText1!.copyWith( + return textTheme.bodyLarge!.copyWith( color: _isDark() ? _kDisabledDark : _kDisabledLight, ); case StepState.error: - return textTheme.bodyText1!.copyWith( + return textTheme.bodyLarge!.copyWith( color: _isDark() ? _kErrorDark : _kErrorLight, ); } @@ -641,7 +641,7 @@ class _StepperState extends State with TickerProviderStateMixin { child: widget.steps[index].label!, ); } - return const SizedBox(); + return const SizedBox.shrink(); } Widget _buildVerticalHeader(int index) { diff --git a/packages/flutter/lib/src/material/tab_indicator.dart b/packages/flutter/lib/src/material/tab_indicator.dart index e28aa8e8711c3..313a55a7e40fe 100644 --- a/packages/flutter/lib/src/material/tab_indicator.dart +++ b/packages/flutter/lib/src/material/tab_indicator.dart @@ -82,9 +82,8 @@ class UnderlineTabIndicator extends Decoration { } class _UnderlinePainter extends BoxPainter { - _UnderlinePainter(this.decoration, VoidCallback? onChanged) - : assert(decoration != null), - super(onChanged); + _UnderlinePainter(this.decoration, super.onChanged) + : assert(decoration != null); final UnderlineTabIndicator decoration; diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 39b1e8d7dc831..ee9db1dcea261 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -98,7 +98,7 @@ class Tab extends StatelessWidget implements PreferredSizeWidget { /// The height of the [Tab]. /// - /// If null, the height will be calculated based on the content of the [Tab]. When `icon` is not + /// If null, the height will be calculated based on the content of the [Tab]. When `icon` is not /// null along with `child` or `text`, the default height is 72.0 pixels. Without an `icon`, the /// height is 46.0 pixels. final double? height; @@ -189,12 +189,12 @@ class _TabStyle extends AnimatedWidget { // the same value of inherit. Force that to be inherit=true here. final TextStyle defaultStyle = (labelStyle ?? tabBarTheme.labelStyle - ?? themeData.primaryTextTheme.bodyText1! + ?? themeData.primaryTextTheme.bodyLarge! ).copyWith(inherit: true); final TextStyle defaultUnselectedStyle = (unselectedLabelStyle ?? tabBarTheme.unselectedLabelStyle ?? labelStyle - ?? themeData.primaryTextTheme.bodyText1! + ?? themeData.primaryTextTheme.bodyLarge! ).copyWith(inherit: true); final TextStyle textStyle = selected ? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value)! @@ -202,7 +202,7 @@ class _TabStyle extends AnimatedWidget { final Color selectedColor = labelColor ?? tabBarTheme.labelColor - ?? themeData.primaryTextTheme.bodyText1!.color!; + ?? themeData.primaryTextTheme.bodyLarge!.color!; final Color unselectedColor = unselectedLabelColor ?? tabBarTheme.unselectedLabelColor ?? selectedColor.withAlpha(0xB2); // 70% alpha @@ -741,7 +741,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// opacity unless [unselectedLabelColor] is non-null. /// /// If this parameter is null, then the color of the [ThemeData.primaryTextTheme]'s - /// bodyText1 text color is used. + /// [TextTheme.bodyLarge] text color is used. final Color? labelColor; /// The color of unselected tab labels. @@ -756,7 +756,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// both selected and unselected label styles. /// /// If this property is null, then the text style of the - /// [ThemeData.primaryTextTheme]'s bodyText1 definition is used. + /// [ThemeData.primaryTextTheme]'s [TextTheme.bodyLarge] definition is used. final TextStyle? labelStyle; /// The padding added to each of the tab labels. @@ -772,7 +772,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// /// If this property is null, then the [labelStyle] value is used. If [labelStyle] /// is null, then the text style of the [ThemeData.primaryTextTheme]'s - /// bodyText1 definition is used. + /// [TextTheme.bodyLarge] definition is used. final TextStyle? unselectedLabelStyle; /// Defines the ink response focus, hover, and splash colors. diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index d2de36ac24223..e60ae98b7f627 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -66,8 +66,10 @@ import 'theme_data.dart'; /// /// See also: /// -/// * [OutlinedButton], a [TextButton] with a border outline. /// * [ElevatedButton], a filled button whose material elevates when pressed. +/// * [FilledButton], a filled button that doesn't elevate when pressed. +/// * [FilledButton.tonal], a filled button variant that uses a secondary fill color. +/// * [OutlinedButton], a button with an outlined border and no fill color. /// * /// * class TextButton extends ButtonStyleButton { @@ -172,7 +174,7 @@ class TextButton extends ButtonStyleButton { ) Color? primary, @Deprecated( - 'Use disabledForegroundColor and disabledForegroundColor instead. ' + 'Use disabledForegroundColor instead. ' 'This feature was deprecated after v3.1.0.' ) Color? onSurface, @@ -338,7 +340,7 @@ class TextButton extends ButtonStyleButton { disabledBackgroundColor: Colors.transparent, shadowColor: theme.shadowColor, elevation: 0, - textStyle: theme.textTheme.button, + textStyle: theme.textTheme.labelLarge, padding: _scaledPadding(context), minimumSize: const Size(64, 36), maximumSize: Size.infinite, diff --git a/packages/flutter/lib/src/material/text_button_theme.dart b/packages/flutter/lib/src/material/text_button_theme.dart index 52968a6c5e9f0..fd8c744eae016 100644 --- a/packages/flutter/lib/src/material/text_button_theme.dart +++ b/packages/flutter/lib/src/material/text_button_theme.dart @@ -16,7 +16,7 @@ import 'theme.dart'; /// overall [Theme]'s [ThemeData.textButtonTheme]. /// /// The [style]'s properties override [TextButton]'s default style, -/// i.e. the [ButtonStyle] returned by [TextButton.defaultStyleOf]. Only +/// i.e. the [ButtonStyle] returned by [TextButton.defaultStyleOf]. Only /// the style's non-null property values or resolved non-null /// [MaterialStateProperty] values are used. /// diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 4ded0a36e56a4..19b69c20622ad 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -36,7 +36,7 @@ typedef InputCounterWidgetBuilder = Widget? Function( required int currentLength, /// The maximum string length that can be entered into the TextField. required int? maxLength, - /// Whether or not the TextField is currently focused. Mainly provided for + /// Whether or not the TextField is currently focused. Mainly provided for /// the [liveRegion] parameter in the [Semantics] widget for accessibility. required bool isFocused, }); @@ -246,7 +246,7 @@ class TextField extends StatefulWidget { /// [maxLength] is set a character counter will be displayed below the /// field showing how many characters have been entered. If the value is /// set to a positive integer it will also display the maximum allowed - /// number of characters to be entered. If the value is set to + /// number of characters to be entered. If the value is set to /// [TextField.noMaxLength] then only the current length is displayed. /// /// After [maxLength] characters have been input, additional input @@ -444,7 +444,7 @@ class TextField extends StatefulWidget { /// /// On Android, the user can hide the keyboard - without changing the focus - /// with the system back button. They can restore the keyboard's visibility - /// by tapping on a text field. The user might hide the keyboard and + /// by tapping on a text field. The user might hide the keyboard and /// switch to a physical keyboard, or they might just need to get it /// out of the way for a moment, to expose something it's /// obscuring. In this case requesting the focus again will not @@ -479,7 +479,7 @@ class TextField extends StatefulWidget { /// /// This text style is also used as the base style for the [decoration]. /// - /// If null, defaults to the `subtitle1` text style from the current [Theme]. + /// If null, defaults to the `titleMedium` text style from the current [Theme]. final TextStyle? style; /// {@macro flutter.widgets.editableText.strutStyle} @@ -733,7 +733,7 @@ class TextField extends StatefulWidget { /// Callback that generates a custom [InputDecoration.counter] widget. /// /// See [InputCounterWidgetBuilder] for an explanation of the passed in - /// arguments. The returned widget will be placed below the line in place of + /// arguments. The returned widget will be placed below the line in place of /// the default widget built when [InputDecoration.counterText] is specified. /// /// The returned widget will be wrapped in a [Semantics] widget for @@ -1197,7 +1197,7 @@ class _TextFieldState extends State with RestorationMixin implements final ThemeData theme = Theme.of(context); final DefaultSelectionStyle selectionStyle = DefaultSelectionStyle.of(context); - final TextStyle style = (theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.subtitle1!).merge(widget.style); + final TextStyle style = (theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.titleMedium!).merge(widget.style); final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.brightness; final TextEditingController controller = _effectiveController; final FocusNode focusNode = _effectiveFocusNode; @@ -1440,7 +1440,7 @@ class _TextFieldState extends State with RestorationMixin implements } TextStyle _m2CounterErrorStyle(BuildContext context) => - Theme.of(context).textTheme.caption!.copyWith(color: Theme.of(context).errorColor); + Theme.of(context).textTheme.bodySmall!.copyWith(color: Theme.of(context).colorScheme.error); // BEGIN GENERATED TOKEN PROPERTIES - TextField diff --git a/packages/flutter/lib/src/material/text_selection.dart b/packages/flutter/lib/src/material/text_selection.dart index 33da727aec0f4..9b4aa1e6fe0f4 100644 --- a/packages/flutter/lib/src/material/text_selection.dart +++ b/packages/flutter/lib/src/material/text_selection.dart @@ -250,7 +250,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo // If there is no option available, build an empty widget. if (itemDatas.isEmpty) { - return const SizedBox(width: 0.0, height: 0.0); + return const SizedBox.shrink(); } return TextSelectionToolbar( diff --git a/packages/flutter/lib/src/material/text_theme.dart b/packages/flutter/lib/src/material/text_theme.dart index b62c2f9d9550c..20a627853e7b5 100644 --- a/packages/flutter/lib/src/material/text_theme.dart +++ b/packages/flutter/lib/src/material/text_theme.dart @@ -10,7 +10,7 @@ import 'typography.dart'; /// Material design text theme. /// /// Definitions for the various typographical styles found in Material Design -/// (e.g., button, caption). Rather than creating a [TextTheme] directly, +/// (e.g., labelLarge, bodySmall). Rather than creating a [TextTheme] directly, /// you can obtain an instance as [Typography.black] or [Typography.white]. /// /// To obtain the current text theme, call [Theme.of] with the current @@ -101,18 +101,70 @@ class TextTheme with Diagnosticable { TextStyle? labelLarge, this.labelMedium, TextStyle? labelSmall, + @Deprecated( + 'Use displayLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline1, + @Deprecated( + 'Use displayMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline2, + @Deprecated( + 'Use displaySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline3, + @Deprecated( + 'Use headlineMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline4, + @Deprecated( + 'Use headlineSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline5, + @Deprecated( + 'Use titleLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline6, + @Deprecated( + 'Use titleMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? subtitle1, + @Deprecated( + 'Use titleSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? subtitle2, + @Deprecated( + 'Use bodyLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? bodyText1, + @Deprecated( + 'Use bodyMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? bodyText2, + @Deprecated( + 'Use bodySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? caption, + @Deprecated( + 'Use labelLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? button, + @Deprecated( + 'Use labelSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? overline, }) : assert( (displayLarge == null && displayMedium == null && displaySmall == null && headlineMedium == null && @@ -232,48 +284,100 @@ class TextTheme with Diagnosticable { final TextStyle? labelSmall; /// Extremely large text. + @Deprecated( + 'Use displayLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline1 => displayLarge; /// Very, very large text. /// /// Used for the date in the dialog shown by [showDatePicker]. + @Deprecated( + 'Use displayMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline2 => displayMedium; /// Very large text. + @Deprecated( + 'Use displaySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline3 => displaySmall; /// Large text. + @Deprecated( + 'Use headlineMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline4 => headlineMedium; /// Used for large text in dialogs (e.g., the month and year in the dialog /// shown by [showDatePicker]). + @Deprecated( + 'Use headlineSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline5 => headlineSmall; /// Used for the primary text in app bars and dialogs (e.g., [AppBar.title] /// and [AlertDialog.title]). + @Deprecated( + 'Use titleLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get headline6 => titleLarge; /// Used for the primary text in lists (e.g., [ListTile.title]). + @Deprecated( + 'Use titleMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get subtitle1 => titleMedium; - /// For medium emphasis text that's a little smaller than [subtitle1]. + /// For medium emphasis text that's a little smaller than [titleMedium]. + @Deprecated( + 'Use titleSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get subtitle2 => titleSmall; - /// Used for emphasizing text that would otherwise be [bodyText2]. + /// Used for emphasizing text that would otherwise be [bodyMedium]. + @Deprecated( + 'Use bodyLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get bodyText1 => bodyLarge; /// The default text style for [Material]. + @Deprecated( + 'Use bodyMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get bodyText2 => bodyMedium; /// Used for auxiliary text associated with images. + @Deprecated( + 'Use bodySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get caption => bodySmall; /// Used for text on [ElevatedButton], [TextButton] and [OutlinedButton]. + @Deprecated( + 'Use labelLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get button => labelLarge; /// The smallest style. /// /// Typically used for captions or to introduce a (larger) headline. + @Deprecated( + 'Use labelSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? get overline => labelSmall; /// Creates a copy of this text theme but with the given fields replaced with @@ -332,18 +436,70 @@ class TextTheme with Diagnosticable { TextStyle? labelLarge, TextStyle? labelMedium, TextStyle? labelSmall, + @Deprecated( + 'Use displayLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline1, + @Deprecated( + 'Use displayMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline2, + @Deprecated( + 'Use displaySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline3, + @Deprecated( + 'Use headlineMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline4, + @Deprecated( + 'Use headlineSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline5, + @Deprecated( + 'Use titleLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? headline6, + @Deprecated( + 'Use titleMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? subtitle1, + @Deprecated( + 'Use titleSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? subtitle2, + @Deprecated( + 'Use bodyLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? bodyText1, + @Deprecated( + 'Use bodyMedium instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? bodyText2, + @Deprecated( + 'Use bodySmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? caption, + @Deprecated( + 'Use labelLarge instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? button, + @Deprecated( + 'Use labelSmall instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) TextStyle? overline, }) { assert( diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart index ee27565303eae..959941f75c676 100644 --- a/packages/flutter/lib/src/material/theme.dart +++ b/packages/flutter/lib/src/material/theme.dart @@ -72,7 +72,7 @@ class Theme extends StatelessWidget { /// Widget build(BuildContext context) { /// return Text( /// 'Example', - /// style: Theme.of(context).textTheme.headline6, + /// style: Theme.of(context).textTheme.titleLarge, /// ); /// } /// ``` @@ -96,7 +96,7 @@ class Theme extends StatelessWidget { /// return Center( /// child: Text( /// 'Example', - /// style: Theme.of(context).textTheme.headline6, + /// style: Theme.of(context).textTheme.titleLarge, /// ), /// ); /// }, diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index b92f5690299db..305b8da54fd92 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -26,6 +26,7 @@ import 'divider_theme.dart'; import 'drawer_theme.dart'; import 'elevated_button_theme.dart'; import 'expansion_tile_theme.dart'; +import 'filled_button_theme.dart'; import 'floating_action_button_theme.dart'; import 'icon_button_theme.dart'; import 'ink_ripple.dart'; @@ -87,7 +88,7 @@ abstract class ThemeExtension> { /// Linearly interpolate with another [ThemeExtension] object. /// /// {@macro dart.ui.shadow.lerp} - ThemeExtension lerp(ThemeExtension? other, double t); + ThemeExtension lerp(covariant ThemeExtension? other, double t); } // Deriving these values is black magic. The spec claims that pressed buttons @@ -199,7 +200,7 @@ enum MaterialTapTargetSize { /// its default background color and the [FloatingActionButton] widget /// uses the color scheme's [ColorScheme.secondary] for its default /// background. By default, the [Text] widget uses -/// [TextTheme.bodyText2], and the color of that [TextStyle] has been +/// [TextTheme.bodyMedium], and the color of that [TextStyle] has been /// changed to purple. /// /// ![](https://flutter.github.io/assets-for-api-docs/assets/material/material_app_theme_data.png) @@ -210,7 +211,7 @@ enum MaterialTapTargetSize { /// colorScheme: ColorScheme.fromSwatch().copyWith( /// secondary: Colors.green, /// ), -/// textTheme: const TextTheme(bodyText2: TextStyle(color: Colors.purple)), +/// textTheme: const TextTheme(bodyMedium: TextStyle(color: Colors.purple)), /// ), /// home: Scaffold( /// appBar: AppBar( @@ -294,7 +295,6 @@ class ThemeData with Diagnosticable { // [colorScheme] is the preferred way to configure colors. The other color // properties (as well as primaryColorBrightness, and primarySwatch) // will gradually be phased out, see https://github.com/flutter/flutter/issues/91772. - Color? backgroundColor, Color? bottomAppBarColor, Brightness? brightness, Color? canvasColor, @@ -304,7 +304,6 @@ class ThemeData with Diagnosticable { Color? dialogBackgroundColor, Color? disabledColor, Color? dividerColor, - Color? errorColor, Color? focusColor, Color? highlightColor, Color? hintColor, @@ -343,6 +342,7 @@ class ThemeData with Diagnosticable { DrawerThemeData? drawerTheme, ElevatedButtonThemeData? elevatedButtonTheme, ExpansionTileThemeData? expansionTileTheme, + FilledButtonThemeData? filledButtonTheme, FloatingActionButtonThemeData? floatingActionButtonTheme, IconButtonThemeData? iconButtonTheme, ListTileThemeData? listTileTheme, @@ -422,6 +422,16 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v3.1.0-0.0.pre.', ) Color? selectedRowColor, + @Deprecated( + 'Use colorScheme.error instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color? errorColor, + @Deprecated( + 'Use colorScheme.background instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color? backgroundColor, }) { // GENERAL CONFIGURATION cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); @@ -505,19 +515,17 @@ class ThemeData with Diagnosticable { primaryColorDark: primaryColorDark, accentColor: accentColor, cardColor: cardColor, - backgroundColor: backgroundColor, - errorColor: errorColor, + backgroundColor: isDark ? Colors.grey[700]! : primarySwatch[200]!, + errorColor: Colors.red[700], brightness: effectiveBrightness, ); selectedRowColor ??= Colors.grey[100]!; unselectedWidgetColor ??= isDark ? Colors.white70 : Colors.black54; // Spec doesn't specify a dark theme secondaryHeaderColor, this is a guess. secondaryHeaderColor ??= isDark ? Colors.grey[700]! : primarySwatch[50]!; - backgroundColor ??= isDark ? Colors.grey[700]! : primarySwatch[200]!; dialogBackgroundColor ??= isDark ? Colors.grey[800]! : Colors.white; indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor; hintColor ??= isDark ? Colors.white60 : Colors.black.withOpacity(0.6); - errorColor ??= Colors.red[700]!; // The default [buttonTheme] is here because it doesn't use the defaults for // [disabledColor], [highlightColor], and [splashColor]. buttonTheme ??= ButtonThemeData( @@ -564,6 +572,7 @@ class ThemeData with Diagnosticable { dividerTheme ??= const DividerThemeData(); drawerTheme ??= const DrawerThemeData(); elevatedButtonTheme ??= const ElevatedButtonThemeData(); + filledButtonTheme ??= const FilledButtonThemeData(); floatingActionButtonTheme ??= const FloatingActionButtonThemeData(); iconButtonTheme ??= const IconButtonThemeData(); listTileTheme ??= const ListTileThemeData(); @@ -584,12 +593,14 @@ class ThemeData with Diagnosticable { tooltipTheme ??= const TooltipThemeData(); expansionTileTheme ??= const ExpansionTileThemeData(); - // DEPRECATED (newest deprecations at the bottom) + // DEPRECATED (newest deprecations at the bottom) accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme); accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); buttonColor ??= isDark ? primarySwatch[600]! : Colors.grey[300]!; fixTextFieldOutlineLabel ??= true; primaryColorBrightness = estimatedPrimaryColorBrightness; + errorColor ??= Colors.red[700]!; + backgroundColor ??= isDark ? Colors.grey[700]! : primarySwatch[200]!; return ThemeData.raw( // For the sanity of the reader, make sure these properties are in the same @@ -610,7 +621,6 @@ class ThemeData with Diagnosticable { useMaterial3: useMaterial3, visualDensity: visualDensity, // COLOR - backgroundColor: backgroundColor, bottomAppBarColor: bottomAppBarColor, canvasColor: canvasColor, cardColor: cardColor, @@ -618,7 +628,6 @@ class ThemeData with Diagnosticable { dialogBackgroundColor: dialogBackgroundColor, disabledColor: disabledColor, dividerColor: dividerColor, - errorColor: errorColor, focusColor: focusColor, highlightColor: highlightColor, hintColor: hintColor, @@ -655,6 +664,7 @@ class ThemeData with Diagnosticable { drawerTheme: drawerTheme, elevatedButtonTheme: elevatedButtonTheme, expansionTileTheme: expansionTileTheme, + filledButtonTheme: filledButtonTheme, floatingActionButtonTheme: floatingActionButtonTheme, iconButtonTheme: iconButtonTheme, listTileTheme: listTileTheme, @@ -684,6 +694,8 @@ class ThemeData with Diagnosticable { androidOverscrollIndicator: androidOverscrollIndicator, toggleableActiveColor: toggleableActiveColor, selectedRowColor: selectedRowColor, + errorColor: errorColor, + backgroundColor: backgroundColor, ); } @@ -716,7 +728,6 @@ class ThemeData with Diagnosticable { // [colorScheme] is the preferred way to configure colors. The other color // properties will gradually be phased out, see // https://github.com/flutter/flutter/issues/91772. - required this.backgroundColor, required this.bottomAppBarColor, required this.canvasColor, required this.cardColor, @@ -724,7 +735,6 @@ class ThemeData with Diagnosticable { required this.dialogBackgroundColor, required this.disabledColor, required this.dividerColor, - required this.errorColor, required this.focusColor, required this.highlightColor, required this.hintColor, @@ -761,6 +771,7 @@ class ThemeData with Diagnosticable { required this.drawerTheme, required this.elevatedButtonTheme, required this.expansionTileTheme, + required this.filledButtonTheme, required this.floatingActionButtonTheme, required this.iconButtonTheme, required this.listTileTheme, @@ -840,6 +851,16 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v3.1.0-0.0.pre.', ) Color? selectedRowColor, + @Deprecated( + 'Use colorScheme.error instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color? errorColor, + @Deprecated( + 'Use colorScheme.background instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color? backgroundColor, }) : // DEPRECATED (newest deprecations at the bottom) // should not be `required`, use getter pattern to avoid breakages. _accentColor = accentColor, @@ -851,6 +872,8 @@ class ThemeData with Diagnosticable { _primaryColorBrightness = primaryColorBrightness, _toggleableActiveColor = toggleableActiveColor, _selectedRowColor = selectedRowColor, + _errorColor = errorColor, + _backgroundColor = backgroundColor, // GENERAL CONFIGURATION assert(applyElevationOverlayColor != null), assert(extensions != null), @@ -863,7 +886,6 @@ class ThemeData with Diagnosticable { assert(useMaterial3 != null), assert(visualDensity != null), // COLOR - assert(backgroundColor != null), assert(bottomAppBarColor != null), assert(canvasColor != null), assert(cardColor != null), @@ -871,7 +893,6 @@ class ThemeData with Diagnosticable { assert(dialogBackgroundColor != null), assert(disabledColor != null), assert(dividerColor != null), - assert(errorColor != null), assert(focusColor != null), assert(highlightColor != null), assert(hintColor != null), @@ -909,6 +930,7 @@ class ThemeData with Diagnosticable { assert(drawerTheme != null), assert(elevatedButtonTheme != null), assert(expansionTileTheme != null), + assert(filledButtonTheme != null), assert(floatingActionButtonTheme != null), assert(iconButtonTheme != null), assert(listTileTheme != null), @@ -926,7 +948,17 @@ class ThemeData with Diagnosticable { assert(textSelectionTheme != null), assert(timePickerTheme != null), assert(toggleButtonsTheme != null), - assert(tooltipTheme != null); + assert(tooltipTheme != null), + // DEPRECATED (newest deprecations at the bottom) + assert(accentColor != null), + assert(accentColorBrightness != null), + assert(accentTextTheme != null), + assert(accentIconTheme != null), + assert(buttonColor != null), + assert(fixTextFieldOutlineLabel != null), + assert(primaryColorBrightness != null), + assert(errorColor != null), + assert(backgroundColor != null); /// Create a [ThemeData] based on the colors in the given [colorScheme] and /// text styles of the optional [textTheme]. @@ -1211,7 +1243,7 @@ class ThemeData with Diagnosticable { /// * Typography: `typography` (see table above) /// /// ### Components - /// * Common buttons: [TextButton], [OutlinedButton], [ElevatedButton] + /// * Common buttons: [ElevatedButton], [FilledButton], [OutlinedButton], [TextButton] /// * FAB: [FloatingActionButton] /// * Extended FAB: [FloatingActionButton.extended] /// * Cards: [Card] @@ -1271,10 +1303,6 @@ class ThemeData with Diagnosticable { // COLOR - /// A color that contrasts with the [primaryColor], e.g. used as the - /// remaining part of a progress bar. - final Color backgroundColor; - /// The default color of the [BottomAppBar]. /// /// This can be overridden by specifying [BottomAppBar.color]. @@ -1311,9 +1339,6 @@ class ThemeData with Diagnosticable { /// [Divider.createBorderSide]. final Color dividerColor; - /// The color to use for input validation errors, e.g. in [TextField] fields. - final Color errorColor; - /// The focus color used indicate that a component has the input focus. final Color focusColor; @@ -1469,6 +1494,10 @@ class ThemeData with Diagnosticable { /// A theme for customizing the visual properties of [ExpansionTile]s. final ExpansionTileThemeData expansionTileTheme; + /// A theme for customizing the appearance and internal layout of + /// [FilledButton]s. + final FilledButtonThemeData filledButtonTheme; + /// A theme for customizing the shape, elevation, and color of a /// [FloatingActionButton]. final FloatingActionButtonThemeData floatingActionButtonTheme; @@ -1584,7 +1613,7 @@ class ThemeData with Diagnosticable { /// /// ```dart /// final ThemeData theme = Theme.of(context); - /// final TextStyle style = theme.textTheme.headline1!.copyWith( + /// final TextStyle style = theme.textTheme.displayLarge!.copyWith( /// color: theme.colorScheme.onSecondary, /// ); /// // ...use style... @@ -1673,6 +1702,24 @@ class ThemeData with Diagnosticable { ) final AndroidOverscrollIndicator? androidOverscrollIndicator; + /// Obsolete property that was used for input validation errors, e.g. in + /// [TextField] fields. Use [ColorScheme.error] instead. + @Deprecated( + 'Use colorScheme.error instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color get errorColor => _errorColor!; + final Color? _errorColor; + + /// Obsolete property that was unused by the framework. + /// Use [ColorScheme.background] instead. + @Deprecated( + 'Use colorScheme.background instead. ' + 'This feature was deprecated after v3.3.0-0.5.pre.', + ) + Color get backgroundColor => _backgroundColor!; + final Color? _backgroundColor; + /// Creates a copy of this theme but with the given fields replaced with the new values. /// /// The [brightness] value is applied to the [colorScheme]. @@ -1698,7 +1745,6 @@ class ThemeData with Diagnosticable { // [colorScheme] is the preferred way to configure colors. The other color // properties will gradually be phased out, see // https://github.com/flutter/flutter/issues/91772. - Color? backgroundColor, Color? bottomAppBarColor, Brightness? brightness, Color? canvasColor, @@ -1707,7 +1753,6 @@ class ThemeData with Diagnosticable { Color? dialogBackgroundColor, Color? disabledColor, Color? dividerColor, - Color? errorColor, Color? focusColor, Color? highlightColor, Color? hintColor, @@ -1744,6 +1789,7 @@ class ThemeData with Diagnosticable { DrawerThemeData? drawerTheme, ElevatedButtonThemeData? elevatedButtonTheme, ExpansionTileThemeData? expansionTileTheme, + FilledButtonThemeData? filledButtonTheme, FloatingActionButtonThemeData? floatingActionButtonTheme, IconButtonThemeData? iconButtonTheme, ListTileThemeData? listTileTheme, @@ -1823,6 +1869,16 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v3.1.0-0.0.pre.', ) Color? selectedRowColor, + @Deprecated( + 'Use colorScheme.error instead. ' + 'This feature was deprecated after v2.6.0-11.0.pre.', + ) + Color? errorColor, + @Deprecated( + 'Use colorScheme.background instead. ' + 'This feature was deprecated after v2.6.0-11.0.pre.', + ) + Color? backgroundColor, }) { cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); return ThemeData.raw( @@ -1844,7 +1900,6 @@ class ThemeData with Diagnosticable { useMaterial3: useMaterial3 ?? this.useMaterial3, visualDensity: visualDensity ?? this.visualDensity, // COLOR - backgroundColor: backgroundColor ?? this.backgroundColor, bottomAppBarColor: bottomAppBarColor ?? this.bottomAppBarColor, canvasColor: canvasColor ?? this.canvasColor, cardColor: cardColor ?? this.cardColor, @@ -1852,7 +1907,6 @@ class ThemeData with Diagnosticable { dialogBackgroundColor: dialogBackgroundColor ?? this.dialogBackgroundColor, disabledColor: disabledColor ?? this.disabledColor, dividerColor: dividerColor ?? this.dividerColor, - errorColor: errorColor ?? this.errorColor, focusColor: focusColor ?? this.focusColor, highlightColor: highlightColor ?? this.highlightColor, hintColor: hintColor ?? this.hintColor, @@ -1889,6 +1943,7 @@ class ThemeData with Diagnosticable { drawerTheme: drawerTheme ?? this.drawerTheme, elevatedButtonTheme: elevatedButtonTheme ?? this.elevatedButtonTheme, expansionTileTheme: expansionTileTheme ?? this.expansionTileTheme, + filledButtonTheme: filledButtonTheme ?? this.filledButtonTheme, floatingActionButtonTheme: floatingActionButtonTheme ?? this.floatingActionButtonTheme, iconButtonTheme: iconButtonTheme ?? this.iconButtonTheme, listTileTheme: listTileTheme ?? this.listTileTheme, @@ -1918,6 +1973,8 @@ class ThemeData with Diagnosticable { androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, toggleableActiveColor: toggleableActiveColor ?? _toggleableActiveColor, selectedRowColor: selectedRowColor ?? _selectedRowColor, + errorColor: errorColor ?? _errorColor, + backgroundColor: backgroundColor ?? _backgroundColor, ); } @@ -2043,7 +2100,6 @@ class ThemeData with Diagnosticable { useMaterial3: t < 0.5 ? a.useMaterial3 : b.useMaterial3, visualDensity: VisualDensity.lerp(a.visualDensity, b.visualDensity, t), // COLOR - backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t)!, bottomAppBarColor: Color.lerp(a.bottomAppBarColor, b.bottomAppBarColor, t)!, canvasColor: Color.lerp(a.canvasColor, b.canvasColor, t)!, cardColor: Color.lerp(a.cardColor, b.cardColor, t)!, @@ -2051,7 +2107,6 @@ class ThemeData with Diagnosticable { dialogBackgroundColor: Color.lerp(a.dialogBackgroundColor, b.dialogBackgroundColor, t)!, disabledColor: Color.lerp(a.disabledColor, b.disabledColor, t)!, dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t)!, - errorColor: Color.lerp(a.errorColor, b.errorColor, t)!, focusColor: Color.lerp(a.focusColor, b.focusColor, t)!, highlightColor: Color.lerp(a.highlightColor, b.highlightColor, t)!, hintColor: Color.lerp(a.hintColor, b.hintColor, t)!, @@ -2088,6 +2143,7 @@ class ThemeData with Diagnosticable { drawerTheme: DrawerThemeData.lerp(a.drawerTheme, b.drawerTheme, t)!, elevatedButtonTheme: ElevatedButtonThemeData.lerp(a.elevatedButtonTheme, b.elevatedButtonTheme, t)!, expansionTileTheme: ExpansionTileThemeData.lerp(a.expansionTileTheme, b.expansionTileTheme, t)!, + filledButtonTheme: FilledButtonThemeData.lerp(a.filledButtonTheme, b.filledButtonTheme, t)!, floatingActionButtonTheme: FloatingActionButtonThemeData.lerp(a.floatingActionButtonTheme, b.floatingActionButtonTheme, t)!, iconButtonTheme: IconButtonThemeData.lerp(a.iconButtonTheme, b.iconButtonTheme, t)!, listTileTheme: ListTileThemeData.lerp(a.listTileTheme, b.listTileTheme, t)!, @@ -2117,6 +2173,8 @@ class ThemeData with Diagnosticable { androidOverscrollIndicator:t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t), selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t), + errorColor: Color.lerp(a.errorColor, b.errorColor, t), + backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), ); } @@ -2144,7 +2202,6 @@ class ThemeData with Diagnosticable { other.useMaterial3 == useMaterial3 && other.visualDensity == visualDensity && // COLOR - other.backgroundColor == backgroundColor && other.bottomAppBarColor == bottomAppBarColor && other.canvasColor == canvasColor && other.cardColor == cardColor && @@ -2152,7 +2209,6 @@ class ThemeData with Diagnosticable { other.dialogBackgroundColor == dialogBackgroundColor && other.disabledColor == disabledColor && other.dividerColor == dividerColor && - other.errorColor == errorColor && other.focusColor == focusColor && other.highlightColor == highlightColor && other.hintColor == hintColor && @@ -2189,6 +2245,7 @@ class ThemeData with Diagnosticable { other.drawerTheme == drawerTheme && other.elevatedButtonTheme == elevatedButtonTheme && other.expansionTileTheme == expansionTileTheme && + other.filledButtonTheme == filledButtonTheme && other.floatingActionButtonTheme == floatingActionButtonTheme && other.iconButtonTheme == iconButtonTheme && other.listTileTheme == listTileTheme && @@ -2217,7 +2274,9 @@ class ThemeData with Diagnosticable { other.primaryColorBrightness == primaryColorBrightness && other.androidOverscrollIndicator == androidOverscrollIndicator && other.toggleableActiveColor == toggleableActiveColor && - other.selectedRowColor == selectedRowColor; + other.selectedRowColor == selectedRowColor && + other.errorColor == errorColor && + other.backgroundColor == backgroundColor; } @override @@ -2242,7 +2301,6 @@ class ThemeData with Diagnosticable { useMaterial3, visualDensity, // COLOR - backgroundColor, bottomAppBarColor, canvasColor, cardColor, @@ -2250,7 +2308,6 @@ class ThemeData with Diagnosticable { dialogBackgroundColor, disabledColor, dividerColor, - errorColor, focusColor, highlightColor, hintColor, @@ -2287,6 +2344,7 @@ class ThemeData with Diagnosticable { drawerTheme, elevatedButtonTheme, expansionTileTheme, + filledButtonTheme, floatingActionButtonTheme, iconButtonTheme, listTileTheme, @@ -2316,6 +2374,8 @@ class ThemeData with Diagnosticable { androidOverscrollIndicator, toggleableActiveColor, selectedRowColor, + errorColor, + backgroundColor, ]; return Object.hashAll(values); } @@ -2342,7 +2402,6 @@ class ThemeData with Diagnosticable { properties.add(DiagnosticsProperty('useMaterial3', useMaterial3, defaultValue: defaultData.useMaterial3, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('visualDensity', visualDensity, defaultValue: defaultData.visualDensity, level: DiagnosticLevel.debug)); // COLORS - properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('bottomAppBarColor', bottomAppBarColor, defaultValue: defaultData.bottomAppBarColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('canvasColor', canvasColor, defaultValue: defaultData.canvasColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('cardColor', cardColor, defaultValue: defaultData.cardColor, level: DiagnosticLevel.debug)); @@ -2350,7 +2409,6 @@ class ThemeData with Diagnosticable { properties.add(ColorProperty('dialogBackgroundColor', dialogBackgroundColor, defaultValue: defaultData.dialogBackgroundColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: defaultData.disabledColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: defaultData.dividerColor, level: DiagnosticLevel.debug)); - properties.add(ColorProperty('errorColor', errorColor, defaultValue: defaultData.errorColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('focusColor', focusColor, defaultValue: defaultData.focusColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('highlightColor', highlightColor, defaultValue: defaultData.highlightColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('hintColor', hintColor, defaultValue: defaultData.hintColor, level: DiagnosticLevel.debug)); @@ -2387,6 +2445,7 @@ class ThemeData with Diagnosticable { properties.add(DiagnosticsProperty('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('elevatedButtonTheme', elevatedButtonTheme, defaultValue: defaultData.elevatedButtonTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('expansionTileTheme', expansionTileTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('filledButtonTheme', filledButtonTheme, defaultValue: defaultData.filledButtonTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('floatingActionButtonTheme', floatingActionButtonTheme, defaultValue: defaultData.floatingActionButtonTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('iconButtonTheme', iconButtonTheme, defaultValue: defaultData.iconButtonTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('listTileTheme', listTileTheme, defaultValue: defaultData.listTileTheme, level: DiagnosticLevel.debug)); @@ -2416,6 +2475,8 @@ class ThemeData with Diagnosticable { properties.add(EnumProperty('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); properties.add(ColorProperty('toggleableActiveColor', toggleableActiveColor, defaultValue: defaultData.toggleableActiveColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('selectedRowColor', selectedRowColor, defaultValue: defaultData.selectedRowColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('errorColor', errorColor, defaultValue: defaultData.errorColor, level: DiagnosticLevel.debug)); + properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor, level: DiagnosticLevel.debug)); } } diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index c8fc468944cf5..c4197924ad767 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -256,7 +256,7 @@ class _TimePickerHeader extends StatelessWidget { const SizedBox(height: 16.0), Text( helpText ?? MaterialLocalizations.of(context).timePickerDialHelpText, - style: TimePickerTheme.of(context).helpTextStyle ?? themeData.textTheme.overline, + style: TimePickerTheme.of(context).helpTextStyle ?? themeData.textTheme.labelSmall, ), controls, ], @@ -297,7 +297,7 @@ class _HourMinuteControl extends StatelessWidget { ? themeData.colorScheme.primary.withOpacity(isDark ? 0.24 : 0.12) : themeData.colorScheme.onSurface.withOpacity(0.12); }); - final TextStyle style = timePickerTheme.hourMinuteTextStyle ?? themeData.textTheme.headline2!; + final TextStyle style = timePickerTheme.hourMinuteTextStyle ?? themeData.textTheme.displayMedium!; final ShapeBorder shape = timePickerTheme.hourMinuteShape ?? _kDefaultShape; final Set states = isSelected ? {MaterialState.selected} : {}; @@ -416,7 +416,7 @@ class _StringFragment extends StatelessWidget { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context); - final TextStyle hourMinuteStyle = timePickerTheme.hourMinuteTextStyle ?? theme.textTheme.headline2!; + final TextStyle hourMinuteStyle = timePickerTheme.hourMinuteTextStyle ?? theme.textTheme.displayMedium!; final Color textColor = timePickerTheme.hourMinuteTextColor ?? theme.colorScheme.onSurface; return ExcludeSemantics( @@ -560,7 +560,7 @@ class _DayPeriodControl extends StatelessWidget { final Set amStates = amSelected ? {MaterialState.selected} : {}; final bool pmSelected = !amSelected; final Set pmStates = pmSelected ? {MaterialState.selected} : {}; - final TextStyle textStyle = timePickerTheme.dayPeriodTextStyle ?? Theme.of(context).textTheme.subtitle1!; + final TextStyle textStyle = timePickerTheme.dayPeriodTextStyle ?? Theme.of(context).textTheme.titleMedium!; final TextStyle amStyle = textStyle.copyWith( color: MaterialStateProperty.resolveAs(textColor, amStates), ); @@ -1181,7 +1181,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { ]; _TappableLabel _buildTappableLabel(TextTheme textTheme, Color color, int value, String label, VoidCallback onTap) { - final TextStyle style = textTheme.bodyText1!.copyWith(color: color); + final TextStyle style = textTheme.bodyLarge!.copyWith(color: color); final double labelScaleFactor = math.min(MediaQuery.of(context).textScaleFactor, 2.0); return _TappableLabel( value: value, @@ -1466,7 +1466,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi final TimeOfDayFormat timeOfDayFormat = MaterialLocalizations.of(context).timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat); final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h; final ThemeData theme = Theme.of(context); - final TextStyle hourMinuteStyle = TimePickerTheme.of(context).hourMinuteTextStyle ?? theme.textTheme.headline2!; + final TextStyle hourMinuteStyle = TimePickerTheme.of(context).hourMinuteTextStyle ?? theme.textTheme.displayMedium!; return Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), @@ -1475,7 +1475,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi children: [ Text( widget.helpText ?? MaterialLocalizations.of(context).timePickerInputHelpText, - style: TimePickerTheme.of(context).helpTextStyle ?? theme.textTheme.overline, + style: TimePickerTheme.of(context).helpTextStyle ?? theme.textTheme.labelSmall, ), const SizedBox(height: 16.0), Row( @@ -1515,7 +1515,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi ExcludeSemantics( child: Text( widget.hourLabelText ?? MaterialLocalizations.of(context).timePickerHourLabel, - style: theme.textTheme.caption, + style: theme.textTheme.bodySmall, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -1547,7 +1547,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi ExcludeSemantics( child: Text( widget.minuteLabelText ?? MaterialLocalizations.of(context).timePickerMinuteLabel, - style: theme.textTheme.caption, + style: theme.textTheme.bodySmall, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -1571,7 +1571,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi if (hourHasError.value || minuteHasError.value) Text( widget.errorInvalidText ?? MaterialLocalizations.of(context).invalidTimeLabel, - style: theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.error), + style: theme.textTheme.bodyMedium!.copyWith(color: theme.colorScheme.error), ) else const SizedBox(height: 2.0), diff --git a/packages/flutter/lib/src/material/time_picker_theme.dart b/packages/flutter/lib/src/material/time_picker_theme.dart index b9ad528c10063..ea6cc946d2f88 100644 --- a/packages/flutter/lib/src/material/time_picker_theme.dart +++ b/packages/flutter/lib/src/material/time_picker_theme.dart @@ -153,13 +153,13 @@ class TimePickerThemeData with Diagnosticable { /// Used to configure the [TextStyle]s for the day period control. /// /// If this is null, the time picker defaults to the overall theme's - /// [TextTheme.subtitle1]. + /// [TextTheme.titleMedium]. final TextStyle? dayPeriodTextStyle; /// Used to configure the [TextStyle]s for the helper text in the header. /// /// If this is null, the time picker defaults to the overall theme's - /// [TextTheme.overline]. + /// [TextTheme.labelSmall]. final TextStyle? helpTextStyle; /// The shape of the [Dialog] that the time picker is presented in. diff --git a/packages/flutter/lib/src/material/toggle_buttons.dart b/packages/flutter/lib/src/material/toggle_buttons.dart index 7fe10a3a61a95..6756fe5a867a6 100644 --- a/packages/flutter/lib/src/material/toggle_buttons.dart +++ b/packages/flutter/lib/src/material/toggle_buttons.dart @@ -710,7 +710,7 @@ class ToggleButtons extends StatelessWidget { } final TextStyle currentTextStyle = textStyle ?? toggleButtonsTheme.textStyle - ?? theme.textTheme.bodyText2!; + ?? theme.textTheme.bodyMedium!; final BoxConstraints? currentConstraints = constraints ?? toggleButtonsTheme.constraints; final Size minimumSize = currentConstraints == null diff --git a/packages/flutter/lib/src/material/toggleable.dart b/packages/flutter/lib/src/material/toggleable.dart index 13c1861675c93..211d8209f0fed 100644 --- a/packages/flutter/lib/src/material/toggleable.dart +++ b/packages/flutter/lib/src/material/toggleable.dart @@ -320,10 +320,10 @@ mixin ToggleableStateMixin on TickerProviderStateMixin mouseCursor: mouseCursor.resolve(states), child: GestureDetector( excludeFromSemantics: !isInteractive, - onTapDown: _handleTapDown, - onTap: _handleTap, - onTapUp: _handleTapEnd, - onTapCancel: _handleTapEnd, + onTapDown: isInteractive ? _handleTapDown : null, + onTap: isInteractive ? _handleTap : null, + onTapUp: isInteractive ? _handleTapEnd : null, + onTapCancel: isInteractive ? _handleTapEnd : null, child: Semantics( enabled: isInteractive, child: CustomPaint( diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart index f5853f0d798f3..344514d29597e 100644 --- a/packages/flutter/lib/src/material/tooltip.dart +++ b/packages/flutter/lib/src/material/tooltip.dart @@ -197,9 +197,9 @@ class Tooltip extends StatefulWidget { /// /// If null, the message's [TextStyle] will be determined based on /// [ThemeData]. If [ThemeData.brightness] is set to [Brightness.dark], - /// [TextTheme.bodyText2] of [ThemeData.textTheme] will be used with + /// [TextTheme.bodyMedium] of [ThemeData.textTheme] will be used with /// [Colors.white]. Otherwise, if [ThemeData.brightness] is set to - /// [Brightness.light], [TextTheme.bodyText2] of [ThemeData.textTheme] will be + /// [Brightness.light], [TextTheme.bodyMedium] of [ThemeData.textTheme] will be /// used with [Colors.black]. final TextStyle? textStyle; @@ -517,7 +517,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { final OverlayState overlayState = Overlay.of( context, debugRequiredFor: widget, - )!; + ); overlayState.insert(_entry!); } SemanticsService.tooltip(_tooltipMessage); @@ -573,7 +573,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { final OverlayState overlayState = Overlay.of( context, debugRequiredFor: widget, - )!; + ); final RenderBox box = context.findRenderObject()! as RenderBox; final Offset target = box.localToGlobal( @@ -696,7 +696,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { // the empty black container so just return the wrapped child as is or // empty container if child is not specified. if (_tooltipMessage.isEmpty) { - return widget.child ?? const SizedBox(); + return widget.child ?? const SizedBox.shrink(); } assert(debugCheckHasOverlay(context)); final ThemeData theme = Theme.of(context); @@ -704,7 +704,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { final TextStyle defaultTextStyle; final BoxDecoration defaultDecoration; if (theme.brightness == Brightness.dark) { - defaultTextStyle = theme.textTheme.bodyText2!.copyWith( + defaultTextStyle = theme.textTheme.bodyMedium!.copyWith( color: Colors.black, fontSize: _getDefaultFontSize(), ); @@ -713,7 +713,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { borderRadius: const BorderRadius.all(Radius.circular(4)), ); } else { - defaultTextStyle = theme.textTheme.bodyText2!.copyWith( + defaultTextStyle = theme.textTheme.bodyMedium!.copyWith( color: Colors.white, fontSize: _getDefaultFontSize(), ); @@ -857,7 +857,7 @@ class _TooltipOverlay extends StatelessWidget { child: ConstrainedBox( constraints: BoxConstraints(minHeight: height), child: DefaultTextStyle( - style: Theme.of(context).textTheme.bodyText2!, + style: Theme.of(context).textTheme.bodyMedium!, child: Container( decoration: decoration, padding: padding, diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart index 4d5a1c85b79b4..e71ba35c7e452 100644 --- a/packages/flutter/lib/src/material/typography.dart +++ b/packages/flutter/lib/src/material/typography.dart @@ -49,7 +49,7 @@ enum ScriptCategory { /// [MaterialLocalizations.scriptCategory] and is created /// by merging a color text theme - [black] for /// [Brightness.light] themes and [white] for [Brightness.dark] -/// themes - and a geometry text theme, one of [englishLike], [dense], +/// themes - and a geometry text theme, one of [englishLike], [dense], /// or [tall], depending on the locale. /// /// To lookup the localized text theme use @@ -610,21 +610,21 @@ class Typography with Diagnosticable { /// The font sizes, weights, and letter spacings in this version match the /// [2018 Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme englishLike2018 = TextTheme( - displayLarge: TextStyle(debugLabel: 'englishLike displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -1.5), - displayMedium: TextStyle(debugLabel: 'englishLike displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -0.5), - displaySmall: TextStyle(debugLabel: 'englishLike displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), - headlineLarge: TextStyle(debugLabel: 'englishLike headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - headlineMedium: TextStyle(debugLabel: 'englishLike headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - headlineSmall: TextStyle(debugLabel: 'englishLike headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), - titleLarge: TextStyle(debugLabel: 'englishLike titleLarge 2018', fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), - titleMedium: TextStyle(debugLabel: 'englishLike titleMedium 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), - titleSmall: TextStyle(debugLabel: 'englishLike titleSmall 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), - bodyLarge: TextStyle(debugLabel: 'englishLike bodyLarge 2018', fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.5), - bodyMedium: TextStyle(debugLabel: 'englishLike bodyMedium 2018', fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), - bodySmall: TextStyle(debugLabel: 'englishLike bodySmall 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.4), - labelLarge: TextStyle(debugLabel: 'englishLike labelLarge 2018', fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.25), - labelMedium: TextStyle(debugLabel: 'englishLike labelMedium 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), - labelSmall: TextStyle(debugLabel: 'englishLike labelSmall 2018', fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), + displayLarge: TextStyle(debugLabel: 'englishLike displayLarge 2018', inherit: false, fontSize: 96.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -1.5), + displayMedium: TextStyle(debugLabel: 'englishLike displayMedium 2018', inherit: false, fontSize: 60.0, fontWeight: FontWeight.w300, textBaseline: TextBaseline.alphabetic, letterSpacing: -0.5), + displaySmall: TextStyle(debugLabel: 'englishLike displaySmall 2018', inherit: false, fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), + headlineLarge: TextStyle(debugLabel: 'englishLike headlineLarge 2018', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), + headlineMedium: TextStyle(debugLabel: 'englishLike headlineMedium 2018', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), + headlineSmall: TextStyle(debugLabel: 'englishLike headlineSmall 2018', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.0), + titleLarge: TextStyle(debugLabel: 'englishLike titleLarge 2018', inherit: false, fontSize: 20.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), + titleMedium: TextStyle(debugLabel: 'englishLike titleMedium 2018', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.15), + titleSmall: TextStyle(debugLabel: 'englishLike titleSmall 2018', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.1), + bodyLarge: TextStyle(debugLabel: 'englishLike bodyLarge 2018', inherit: false, fontSize: 16.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.5), + bodyMedium: TextStyle(debugLabel: 'englishLike bodyMedium 2018', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.25), + bodySmall: TextStyle(debugLabel: 'englishLike bodySmall 2018', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 0.4), + labelLarge: TextStyle(debugLabel: 'englishLike labelLarge 2018', inherit: false, fontSize: 14.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.25), + labelMedium: TextStyle(debugLabel: 'englishLike labelMedium 2018', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), + labelSmall: TextStyle(debugLabel: 'englishLike labelSmall 2018', inherit: false, fontSize: 10.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic, letterSpacing: 1.5), ); /// Defines text geometry for dense scripts, such as Chinese, Japanese @@ -653,21 +653,21 @@ class Typography with Diagnosticable { /// The font sizes, weights, and letter spacings in this version match the /// 2018 [Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme dense2018 = TextTheme( - displayLarge: TextStyle(debugLabel: 'dense displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), - displayMedium: TextStyle(debugLabel: 'dense displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), - displaySmall: TextStyle(debugLabel: 'dense displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineLarge: TextStyle(debugLabel: 'dense headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineMedium: TextStyle(debugLabel: 'dense headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - headlineSmall: TextStyle(debugLabel: 'dense headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleLarge: TextStyle(debugLabel: 'dense titleLarge 2018', fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - titleMedium: TextStyle(debugLabel: 'dense titleMedium 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - titleSmall: TextStyle(debugLabel: 'dense titleSmall 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - bodyLarge: TextStyle(debugLabel: 'dense bodyLarge 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - bodyMedium: TextStyle(debugLabel: 'dense bodyMedium 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - bodySmall: TextStyle(debugLabel: 'dense bodySmall 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelLarge: TextStyle(debugLabel: 'dense labelLarge 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), - labelMedium: TextStyle(debugLabel: 'dense labelMedium 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), - labelSmall: TextStyle(debugLabel: 'dense labelSmall 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + displayLarge: TextStyle(debugLabel: 'dense displayLarge 2018', inherit: false, fontSize: 96.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), + displayMedium: TextStyle(debugLabel: 'dense displayMedium 2018', inherit: false, fontSize: 60.0, fontWeight: FontWeight.w100, textBaseline: TextBaseline.ideographic), + displaySmall: TextStyle(debugLabel: 'dense displaySmall 2018', inherit: false, fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headlineLarge: TextStyle(debugLabel: 'dense headlineLarge 2018', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headlineMedium: TextStyle(debugLabel: 'dense headlineMedium 2018', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + headlineSmall: TextStyle(debugLabel: 'dense headlineSmall 2018', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + titleLarge: TextStyle(debugLabel: 'dense titleLarge 2018', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + titleMedium: TextStyle(debugLabel: 'dense titleMedium 2018', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + titleSmall: TextStyle(debugLabel: 'dense titleSmall 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + bodyLarge: TextStyle(debugLabel: 'dense bodyLarge 2018', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + bodyMedium: TextStyle(debugLabel: 'dense bodyMedium 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + bodySmall: TextStyle(debugLabel: 'dense bodySmall 2018', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + labelLarge: TextStyle(debugLabel: 'dense labelLarge 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.ideographic), + labelMedium: TextStyle(debugLabel: 'dense labelMedium 2018', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), + labelSmall: TextStyle(debugLabel: 'dense labelSmall 2018', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.ideographic), ); /// Defines text geometry for tall scripts, such as Farsi, Hindi, and Thai. @@ -694,21 +694,21 @@ class Typography with Diagnosticable { /// The font sizes, weights, and letter spacings in this version match the /// 2018 [Material Design specification](https://material.io/go/design-typography#typography-styles). static const TextTheme tall2018 = TextTheme( - displayLarge: TextStyle(debugLabel: 'tall displayLarge 2018', fontSize: 96.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displayMedium: TextStyle(debugLabel: 'tall displayMedium 2018', fontSize: 60.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - displaySmall: TextStyle(debugLabel: 'tall displaySmall 2018', fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineLarge: TextStyle(debugLabel: 'tall headlineLarge 2018', fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineMedium: TextStyle(debugLabel: 'tall headlineMedium 2018', fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - headlineSmall: TextStyle(debugLabel: 'tall headlineSmall 2018', fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleLarge: TextStyle(debugLabel: 'tall titleLarge 2018', fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - titleMedium : TextStyle(debugLabel: 'tall titleMedium 2018', fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - titleSmall: TextStyle(debugLabel: 'tall titleSmall 2018', fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), - bodyLarge: TextStyle(debugLabel: 'tall bodyLarge 2018', fontSize: 17.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - bodyMedium: TextStyle(debugLabel: 'tall bodyMedium 2018', fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - bodySmall: TextStyle(debugLabel: 'tall bodySmall 2018', fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelLarge: TextStyle(debugLabel: 'tall labelLarge 2018', fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), - labelMedium: TextStyle(debugLabel: 'tall labelMedium 2018', fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), - labelSmall: TextStyle(debugLabel: 'tall labelSmall 2018', fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + displayLarge: TextStyle(debugLabel: 'tall displayLarge 2018', inherit: false, fontSize: 96.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + displayMedium: TextStyle(debugLabel: 'tall displayMedium 2018', inherit: false, fontSize: 60.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + displaySmall: TextStyle(debugLabel: 'tall displaySmall 2018', inherit: false, fontSize: 48.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headlineLarge: TextStyle(debugLabel: 'tall headlineLarge 2018', inherit: false, fontSize: 40.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headlineMedium: TextStyle(debugLabel: 'tall headlineMedium 2018', inherit: false, fontSize: 34.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + headlineSmall: TextStyle(debugLabel: 'tall headlineSmall 2018', inherit: false, fontSize: 24.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + titleLarge: TextStyle(debugLabel: 'tall titleLarge 2018', inherit: false, fontSize: 21.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + titleMedium : TextStyle(debugLabel: 'tall titleMedium 2018', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + titleSmall: TextStyle(debugLabel: 'tall titleSmall 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w500, textBaseline: TextBaseline.alphabetic), + bodyLarge: TextStyle(debugLabel: 'tall bodyLarge 2018', inherit: false, fontSize: 17.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + bodyMedium: TextStyle(debugLabel: 'tall bodyMedium 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + bodySmall: TextStyle(debugLabel: 'tall bodySmall 2018', inherit: false, fontSize: 13.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + labelLarge: TextStyle(debugLabel: 'tall labelLarge 2018', inherit: false, fontSize: 15.0, fontWeight: FontWeight.w700, textBaseline: TextBaseline.alphabetic), + labelMedium: TextStyle(debugLabel: 'tall labelMedium 2018', inherit: false, fontSize: 12.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), + labelSmall: TextStyle(debugLabel: 'tall labelSmall 2018', inherit: false, fontSize: 11.0, fontWeight: FontWeight.w400, textBaseline: TextBaseline.alphabetic), ); /// Defines text geometry for [ScriptCategory.englishLike] scripts, such as diff --git a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart index a49f8da2bf80d..97445ef405308 100644 --- a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart +++ b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart @@ -148,7 +148,7 @@ class _AccountDetailsState extends State<_AccountDetails> with SingleTickerProvi child: Padding( padding: const EdgeInsets.symmetric(vertical: 2.0), child: DefaultTextStyle( - style: theme.primaryTextTheme.bodyText1!, + style: theme.primaryTextTheme.bodyLarge!, overflow: TextOverflow.ellipsis, child: widget.accountName!, ), @@ -160,7 +160,7 @@ class _AccountDetailsState extends State<_AccountDetails> with SingleTickerProvi child: Padding( padding: const EdgeInsets.symmetric(vertical: 2.0), child: DefaultTextStyle( - style: theme.primaryTextTheme.bodyText2!, + style: theme.primaryTextTheme.bodyMedium!, overflow: TextOverflow.ellipsis, child: widget.accountEmail!, ), diff --git a/packages/flutter/lib/src/painting/beveled_rectangle_border.dart b/packages/flutter/lib/src/painting/beveled_rectangle_border.dart index 8e7406c673499..084daf86b4f6e 100644 --- a/packages/flutter/lib/src/painting/beveled_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/beveled_rectangle_border.dart @@ -9,7 +9,6 @@ import 'package:flutter/foundation.dart'; import 'basic_types.dart'; import 'border_radius.dart'; import 'borders.dart'; -import 'edge_insets.dart'; /// A rectangular border with flattened or "beveled" corners. /// @@ -40,18 +39,6 @@ class BeveledRectangleBorder extends OutlinedBorder { /// [getOuterPath]. final BorderRadiusGeometry borderRadius; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) { return BeveledRectangleBorder( @@ -125,21 +112,7 @@ class BeveledRectangleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { - final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect; - break; - } - - return _getPath(adjustedRect); + return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.strokeInset)); } @override @@ -157,18 +130,7 @@ class BeveledRectangleBorder extends OutlinedBorder { break; case BorderStyle.solid: final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect; - break; - case StrokeAlign.center: - adjustedRect = borderRect.inflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect.inflate(side.width); - break; - } + final RRect adjustedRect = borderRect.inflate(side.strokeOutset); final Path path = _getPath(adjustedRect) ..addPath(getInnerPath(rect, textDirection: textDirection), Offset.zero); canvas.drawPath(path, side.toPaint()); diff --git a/packages/flutter/lib/src/painting/borders.dart b/packages/flutter/lib/src/painting/borders.dart index f112465d71ec9..4e3910bff5639 100644 --- a/packages/flutter/lib/src/painting/borders.dart +++ b/packages/flutter/lib/src/painting/borders.dart @@ -21,27 +21,6 @@ enum BorderStyle { // if you add more, think about how they will lerp } -/// The relative position of the stroke on a [BorderSide] in a [Border] or [OutlinedBorder]. -/// When set to [inside], the stroke is drawn completely inside the widget. -/// For [center] and [outside], a property such as [Container.clipBehavior] -/// can be used in an outside widget to clip it. -/// If [Container.decoration] has a border, the container may incorporate -/// [BorderSide.width] as additional padding: -/// - [inside] provides padding with full [BorderSide.width]. -/// - [center] provides padding with half [BorderSide.width]. -/// - [outside] provides zero padding, as stroke is drawn entirely outside. -enum StrokeAlign { - /// The border is drawn on the inside of the border path. - inside, - - /// The border is drawn on the center of the border path, with half of the - /// [BorderSide.width] on the inside, and the other half on the outside of the path. - center, - - /// The border is drawn on the outside of the border path. - outside, -} - /// A side of a border of a box. /// /// A [Border] consists of four [BorderSide] objects: [Border.top], @@ -51,7 +30,6 @@ enum StrokeAlign { /// rendering. A more involved explanation is present in [BorderSide.width]. /// /// {@tool snippet} -/// /// This sample shows how [BorderSide] objects can be used in a [Container], via /// a [BoxDecoration] and a [Border], to decorate some [Text]. In this example, /// the text has a thick bar above it that is light blue, and a thick bar below @@ -79,7 +57,7 @@ enum StrokeAlign { /// ([TableBorder.horizontalInside] and [TableBorder.verticalInside]), both /// of which are also [BorderSide] objects. @immutable -class BorderSide { +class BorderSide with Diagnosticable { /// Creates the side of a border. /// /// By default, the border is 1.0 logical pixels wide and solid black. @@ -87,11 +65,12 @@ class BorderSide { this.color = const Color(0xFF000000), this.width = 1.0, this.style = BorderStyle.solid, - this.strokeAlign = StrokeAlign.inside, + this.strokeAlign = strokeAlignInside, }) : assert(color != null), assert(width != null), assert(width >= 0.0), - assert(style != null); + assert(style != null), + assert(strokeAlign != null); /// Creates a [BorderSide] that represents the addition of the two given /// [BorderSide]s. @@ -124,6 +103,7 @@ class BorderSide { return BorderSide( color: a.color, // == b.color width: a.width + b.width, + strokeAlign: math.max(a.strokeAlign, b.strokeAlign), style: a.style, // == b.style ); } @@ -151,20 +131,57 @@ class BorderSide { /// A hairline black border that is not rendered. static const BorderSide none = BorderSide(width: 0.0, style: BorderStyle.none); - /// The direction of where the border will be drawn relative to the container. - final StrokeAlign strokeAlign; + /// The relative position of the stroke on a [BorderSide] in an + /// [OutlinedBorder] or [Border]. + /// + /// Values typically range from -1.0 ([strokeAlignInside], inside border, + /// default) to 1.0 ([strokeAlignOutside], outside border), without any + /// bound constraints (e.g., a value of -2.0 is is not typical, but allowed). + /// A value of 0 ([strokeAlignCenter]) will center the border on the edge + /// of the widget. + /// + /// When set to [strokeAlignInside], the stroke is drawn completely inside + /// the widget. For [strokeAlignCenter] and [strokeAlignOutside], a property + /// such as [Container.clipBehavior] can be used in an outside widget to clip + /// it. If [Container.decoration] has a border, the container may incorporate + /// [width] as additional padding: + /// - [strokeAlignInside] provides padding with full [width]. + /// - [strokeAlignCenter] provides padding with half [width]. + /// - [strokeAlignOutside] provides zero padding, as stroke is drawn entirely outside. + /// + /// {@tool dartpad} + /// This example shows an animation of how `strokeAlign` affects the drawing + /// when applied to borders of various shapes. + /// + /// ** See code in examples/api/lib/painting/borders/border_side.stroke_align.0.dart ** + /// {@end-tool} + final double strokeAlign; + + /// The border is drawn fully inside of the border path. + /// + /// This is the default. + static const double strokeAlignInside = -1.0; + + /// The border is drawn on the center of the border path, with half of the + /// [BorderSide.width] on the inside, and the other half on the outside of + /// the path. + static const double strokeAlignCenter = 0.0; + + /// The border is drawn on the outside of the border path. + static const double strokeAlignOutside = 1.0; /// Creates a copy of this border but with the given fields replaced with the new values. BorderSide copyWith({ Color? color, double? width, BorderStyle? style, + double? strokeAlign, }) { - assert(width == null || width >= 0.0); return BorderSide( color: color ?? this.color, width: width ?? this.width, style: style ?? this.style, + strokeAlign: strokeAlign ?? this.strokeAlign, ); } @@ -229,8 +246,7 @@ class BorderSide { return true; } return a.style == b.style - && a.color == b.color - && a.strokeAlign == b.strokeAlign; + && a.color == b.color; } /// Linearly interpolate between two border sides. @@ -278,13 +294,10 @@ class BorderSide { break; } if (a.strokeAlign != b.strokeAlign) { - // When strokeAlign changes, lerp to 0, then from 0 to the target width. - // All StrokeAlign values share a common zero width state. - final StrokeAlign strokeAlign = t > 0.5 ? b.strokeAlign : a.strokeAlign; return BorderSide( color: Color.lerp(colorA, colorB, t)!, - width: t > 0.5 ? ui.lerpDouble(0, b.width, t * 2 - 1)! : ui.lerpDouble(a.width, 0, t * 2)!, - strokeAlign: strokeAlign, + width: width, + strokeAlign: ui.lerpDouble(a.strokeAlign, b.strokeAlign, t)!, ); } return BorderSide( @@ -294,6 +307,26 @@ class BorderSide { ); } + /// Get the amount of the stroke width that lies inside of the [BorderSide]. + /// + /// For example, this will return the [width] for a [strokeAlign] of -1, half + /// the [width] for a [strokeAlign] of 0, and 0 for a [strokeAlign] of 1. + double get strokeInset => width * (1 - (1 + strokeAlign) / 2); + + /// Get the amount of the stroke width that lies outside of the [BorderSide]. + /// + /// For example, this will return 0 for a [strokeAlign] of -1, half the + /// [width] for a [strokeAlign] of 0, and the [width] for a [strokeAlign] + /// of 1. + double get strokeOutset => width * (1 + strokeAlign) / 2; + + /// The offset of the stroke, taking into account the stroke alignment. + /// + /// For example, this will return the negative [width] of the stroke + /// for a [strokeAlign] of -1, 0 for a [strokeAlign] of 0, and the + /// [width] for a [strokeAlign] of -1. + double get strokeOffset => width * strokeAlign; + @override bool operator ==(Object other) { if (identical(this, other)) { @@ -313,11 +346,15 @@ class BorderSide { int get hashCode => Object.hash(color, width, style, strokeAlign); @override - String toString() { - if (strokeAlign == StrokeAlign.inside) { - return '${objectRuntimeType(this, 'BorderSide')}($color, ${width.toStringAsFixed(1)}, $style)'; - } - return '${objectRuntimeType(this, 'BorderSide')}($color, ${width.toStringAsFixed(1)}, $style, $strokeAlign)'; + String toStringShort() => 'BorderSide'; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('color', color, defaultValue: const Color(0xFF000000))); + properties.add(DoubleProperty('width', width, defaultValue: 1.0)); + properties.add(DoubleProperty('strokeAlign', strokeAlign, defaultValue: strokeAlignInside)); + properties.add(EnumProperty('style', style, defaultValue: BorderStyle.solid)); } } @@ -629,6 +666,9 @@ abstract class OutlinedBorder extends ShapeBorder { /// The value of [side] must not be null. const OutlinedBorder({ this.side = BorderSide.none }) : assert(side != null); + @override + EdgeInsetsGeometry get dimensions => EdgeInsets.all(math.max(side.strokeInset, 0)); + /// The border outline's color and weight. /// /// If [side] is [BorderSide.none], which is the default, an outline is not drawn. diff --git a/packages/flutter/lib/src/painting/box_border.dart b/packages/flutter/lib/src/painting/box_border.dart index bf6fb1d733f99..650bd5d5d8436 100644 --- a/packages/flutter/lib/src/painting/box_border.dart +++ b/packages/flutter/lib/src/painting/box_border.dart @@ -231,62 +231,22 @@ abstract class BoxBorder extends ShapeBorder { ..strokeWidth = 0.0; canvas.drawRRect(borderRadius.toRRect(rect), paint); } else { - if (side.strokeAlign == StrokeAlign.inside) { - final RRect outer = borderRadius.toRRect(rect); - final RRect inner = outer.deflate(width); - canvas.drawDRRect(outer, inner, paint); - } else { - final Rect inner; - final Rect outer; - if (side.strokeAlign == StrokeAlign.center) { - inner = rect.deflate(width / 2); - outer = rect.inflate(width / 2); - } else { - inner = rect; - outer = rect.inflate(width); - } - canvas.drawDRRect(borderRadius.toRRect(outer), borderRadius.toRRect(inner), paint); - } + final RRect borderRect = borderRadius.toRRect(rect); + final RRect inner = borderRect.deflate(side.strokeInset); + final RRect outer = borderRect.inflate(side.strokeOutset); + canvas.drawDRRect(outer, inner, paint); } } static void _paintUniformBorderWithCircle(Canvas canvas, Rect rect, BorderSide side) { assert(side.style != BorderStyle.none); - final double width = side.width; - final Paint paint = side.toPaint(); - final double radius; - switch (side.strokeAlign) { - case StrokeAlign.inside: - radius = (rect.shortestSide - width) / 2.0; - break; - case StrokeAlign.center: - radius = rect.shortestSide / 2.0; - break; - case StrokeAlign.outside: - radius = (rect.shortestSide + width) / 2.0; - break; - } - canvas.drawCircle(rect.center, radius, paint); + final double radius = (rect.shortestSide + side.strokeOffset) / 2; + canvas.drawCircle(rect.center, radius, side.toPaint()); } static void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect, BorderSide side) { assert(side.style != BorderStyle.none); - final double width = side.width; - final Paint paint = side.toPaint(); - final Rect rectToBeDrawn; - switch (side.strokeAlign) { - case StrokeAlign.inside: - rectToBeDrawn = rect.deflate(width / 2.0); - break; - case StrokeAlign.center: - rectToBeDrawn = rect; - break; - case StrokeAlign.outside: - rectToBeDrawn = rect.inflate(width / 2.0); - break; - } - - canvas.drawRect(rectToBeDrawn, paint); + canvas.drawRect(rect.inflate(side.strokeOffset / 2), side.toPaint()); } } @@ -400,7 +360,7 @@ class Border extends BoxBorder { Color color = const Color(0xFF000000), double width = 1.0, BorderStyle style = BorderStyle.solid, - StrokeAlign strokeAlign = StrokeAlign.inside, + double strokeAlign = BorderSide.strokeAlignInside, }) { final BorderSide side = BorderSide(color: color, width: width, style: style, strokeAlign: strokeAlign); return Border.fromBorderSide(side); @@ -442,17 +402,10 @@ class Border extends BoxBorder { @override EdgeInsetsGeometry get dimensions { - if (isUniform) { - switch (top.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(top.width); - case StrokeAlign.center: - return EdgeInsets.all(top.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } + if (_widthIsUniform) { + return EdgeInsets.all(top.strokeInset); } - return EdgeInsets.fromLTRB(left.width, top.width, right.width, bottom.width); + return EdgeInsets.fromLTRB(left.strokeInset, top.strokeInset, right.strokeInset, bottom.strokeInset); } @override @@ -474,7 +427,7 @@ class Border extends BoxBorder { } bool get _strokeAlignIsUniform { - final StrokeAlign topStrokeAlign = top.strokeAlign; + final double topStrokeAlign = top.strokeAlign; return right.strokeAlign == topStrokeAlign && bottom.strokeAlign == topStrokeAlign && left.strokeAlign == topStrokeAlign; @@ -581,7 +534,7 @@ class Border extends BoxBorder { BoxBorder._paintUniformBorderWithCircle(canvas, rect, top); break; case BoxShape.rectangle: - if (borderRadius != null) { + if (borderRadius != null && borderRadius != BorderRadius.zero) { BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius); return; } @@ -619,9 +572,9 @@ class Border extends BoxBorder { return true; }()); assert(() { - if (!_strokeAlignIsUniform || top.strokeAlign != StrokeAlign.inside) { + if (!_strokeAlignIsUniform || top.strokeAlign != BorderSide.strokeAlignInside) { throw FlutterError.fromParts([ - ErrorSummary('A Border can only draw strokeAlign different than StrokeAlign.inside on uniform borders.'), + ErrorSummary('A Border can only draw strokeAlign different than BorderSide.strokeAlignInside on uniform borders.'), ]); } return true; @@ -753,16 +706,9 @@ class BorderDirectional extends BoxBorder { @override EdgeInsetsGeometry get dimensions { if (isUniform) { - switch (top.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsetsDirectional.all(top.width); - case StrokeAlign.center: - return EdgeInsetsDirectional.all(top.width / 2); - case StrokeAlign.outside: - return EdgeInsetsDirectional.zero; - } + return EdgeInsetsDirectional.all(top.strokeInset); } - return EdgeInsetsDirectional.fromSTEB(start.width, top.width, end.width, bottom.width); + return EdgeInsetsDirectional.fromSTEB(start.strokeInset, top.strokeInset, end.strokeInset, bottom.strokeInset); } @override @@ -796,7 +742,7 @@ class BorderDirectional extends BoxBorder { } bool get _strokeAlignIsUniform { - final StrokeAlign topStrokeAlign = top.strokeAlign; + final double topStrokeAlign = top.strokeAlign; return start.strokeAlign == topStrokeAlign && bottom.strokeAlign == topStrokeAlign && end.strokeAlign == topStrokeAlign; @@ -939,7 +885,7 @@ class BorderDirectional extends BoxBorder { BoxBorder._paintUniformBorderWithCircle(canvas, rect, top); break; case BoxShape.rectangle: - if (borderRadius != null) { + if (borderRadius != null && borderRadius != BorderRadius.zero) { BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius); return; } @@ -952,7 +898,7 @@ class BorderDirectional extends BoxBorder { assert(borderRadius == null, 'A borderRadius can only be given for uniform borders.'); assert(shape == BoxShape.rectangle, 'A border can only be drawn as a circle if it is uniform.'); - assert(_strokeAlignIsUniform && top.strokeAlign == StrokeAlign.inside, 'A Border can only draw strokeAlign different than StrokeAlign.inside on uniform borders.'); + assert(_strokeAlignIsUniform && top.strokeAlign == BorderSide.strokeAlignInside, 'A Border can only draw strokeAlign different than strokeAlignInside on uniform borders.'); final BorderSide left, right; assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.'); diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index 01164b445415f..960d05627385a 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -391,9 +391,8 @@ class BoxDecoration extends Decoration { /// An object that paints a [BoxDecoration] into a canvas. class _BoxDecorationPainter extends BoxPainter { - _BoxDecorationPainter(this._decoration, VoidCallback? onChanged) - : assert(_decoration != null), - super(onChanged); + _BoxDecorationPainter(this._decoration, super.onChanged) + : assert(_decoration != null); final BoxDecoration _decoration; @@ -431,7 +430,7 @@ class _BoxDecorationPainter extends BoxPainter { canvas.drawCircle(center, radius, paint); break; case BoxShape.rectangle: - if (_decoration.borderRadius == null) { + if (_decoration.borderRadius == null || _decoration.borderRadius == BorderRadius.zero) { canvas.drawRect(rect, paint); } else { canvas.drawRRect(_decoration.borderRadius!.resolve(textDirection).toRRect(rect), paint); diff --git a/packages/flutter/lib/src/painting/circle_border.dart b/packages/flutter/lib/src/painting/circle_border.dart index 730cde691be9c..f43774d7db325 100644 --- a/packages/flutter/lib/src/painting/circle_border.dart +++ b/packages/flutter/lib/src/painting/circle_border.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'basic_types.dart'; import 'borders.dart'; -import 'edge_insets.dart'; /// A border that fits a circle within the available space. /// @@ -45,18 +44,6 @@ class CircleBorder extends OutlinedBorder { /// When 1.0, it draws an oval touching all sides of the rectangle. final double eccentricity; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) => CircleBorder(side: side.scale(t), eccentricity: eccentricity); @@ -84,25 +71,12 @@ class CircleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { - final double delta; - switch (side.strokeAlign) { - case StrokeAlign.inside: - delta = side.width; - break; - case StrokeAlign.center: - delta = side.width / 2.0; - break; - case StrokeAlign.outside: - delta = 0; - break; - } - final Rect adjustedRect = _adjustRect(rect).deflate(delta); - return Path()..addOval(adjustedRect); + return Path()..addOval(_adjustRect(rect).deflate(side.strokeInset)); } @override Path getOuterPath(Rect rect, { TextDirection? textDirection }) { - return Path()..addOval(_adjustRect(rect)); + return Path()..addOval(_adjustRect(rect)); } @override @@ -128,35 +102,11 @@ class CircleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - if (eccentricity != 0.0) { - final Rect borderRect = _adjustRect(rect); - final Rect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width / 2.0); - break; - case StrokeAlign.center: - adjustedRect = borderRect; - break; - case StrokeAlign.outside: - adjustedRect = borderRect.inflate(side.width / 2.0); - break; - } - canvas.drawOval(adjustedRect, side.toPaint()); + if (eccentricity == 0.0) { + canvas.drawCircle(rect.center, (rect.shortestSide + side.strokeOffset) / 2, side.toPaint()); } else { - final double radius; - switch (side.strokeAlign) { - case StrokeAlign.inside: - radius = (rect.shortestSide - side.width) / 2.0; - break; - case StrokeAlign.center: - radius = rect.shortestSide / 2.0; - break; - case StrokeAlign.outside: - radius = (rect.shortestSide + side.width) / 2.0; - break; - } - canvas.drawCircle(rect.center, radius, side.toPaint()); + final Rect borderRect = _adjustRect(rect); + canvas.drawOval(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } } } diff --git a/packages/flutter/lib/src/painting/continuous_rectangle_border.dart b/packages/flutter/lib/src/painting/continuous_rectangle_border.dart index b3456c907df4d..f82641c7e4cfa 100644 --- a/packages/flutter/lib/src/painting/continuous_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/continuous_rectangle_border.dart @@ -148,9 +148,10 @@ class ContinuousRectangleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final Path path = getOuterPath(rect, textDirection: textDirection); - final Paint paint = side.toPaint(); - canvas.drawPath(path, paint); + canvas.drawPath( + getOuterPath(rect, textDirection: textDirection), + side.toPaint(), + ); break; } } diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart index eaf03ba76bbbe..103b2b0fbc738 100644 --- a/packages/flutter/lib/src/painting/gradient.dart +++ b/packages/flutter/lib/src/painting/gradient.dart @@ -579,7 +579,7 @@ class LinearGradient extends Gradient { /// which will make the rendered gradient appear to be pointed or directed in the /// direction of the [focal] point. This is only important if [focal] and [center] /// are not equal or [focalRadius] > 0.0 (as this case is visually identical to a -/// normal radial gradient). One important case to avoid is having [focal] and +/// normal radial gradient). One important case to avoid is having [focal] and /// [center] both resolve to [Offset.zero] when [focalRadius] > 0.0. In such a case, /// a valid shader cannot be created by the framework. /// @@ -687,7 +687,7 @@ class RadialGradient extends Gradient { /// ![](https://flutter.github.io/assets-for-api-docs/assets/dart-ui/tile_mode_repeated_radialWithFocal.png) final TileMode tileMode; - /// The focal point of the gradient. If specified, the gradient will appear + /// The focal point of the gradient. If specified, the gradient will appear /// to be focused along the vector from [center] to focal. /// /// See [center] for a description of how the coordinates are mapped. diff --git a/packages/flutter/lib/src/painting/inline_span.dart b/packages/flutter/lib/src/painting/inline_span.dart index 0050607456618..242e0d7438c0e 100644 --- a/packages/flutter/lib/src/painting/inline_span.dart +++ b/packages/flutter/lib/src/painting/inline_span.dart @@ -68,7 +68,7 @@ class InlineSpanSemanticsInformation { /// The text info for a [PlaceholderSpan]. static const InlineSpanSemanticsInformation placeholder = InlineSpanSemanticsInformation('\uFFFC', isPlaceholder: true); - /// The text value, if any. For [PlaceholderSpan]s, this will be the unicode + /// The text value, if any. For [PlaceholderSpan]s, this will be the unicode /// placeholder value. final String text; @@ -280,7 +280,7 @@ abstract class InlineSpan extends DiagnosticableTree { /// Walks the [InlineSpan] tree and accumulates a list of /// [InlineSpanSemanticsInformation] objects. /// - /// This method should not be directly called. Use + /// This method should not be directly called. Use /// [getSemanticsInformation] instead. /// /// [PlaceholderSpan]s in the tree will be represented with a diff --git a/packages/flutter/lib/src/painting/matrix_utils.dart b/packages/flutter/lib/src/painting/matrix_utils.dart index 0573b6e6aa63f..d7c215213224a 100644 --- a/packages/flutter/lib/src/painting/matrix_utils.dart +++ b/packages/flutter/lib/src/painting/matrix_utils.dart @@ -245,7 +245,7 @@ class MatrixUtils { // since we know that Z=0.0. We can also get rid of the 3rd row because // we ignore the resulting Z coordinate. Finally we can get rid of the // last row if we don't have a perspective transform since we can verify - // that the results are 1.0 for all points. This gets us down to 16 + // that the results are 1.0 for all points. This gets us down to 16 // multiplies and 16 adds in the non-perspective case and 24 of each for // the perspective case. (Plus the 12 comparisons to turn them back into // a bounding box.) @@ -282,7 +282,7 @@ class MatrixUtils { // continue to hold with respect to the non-normalized coordinates so // we can still save a lot of multiplications by computing the 4 // non-normalized coordinates using relative additions before we normalize - // them and they lose their "pseudo-parallelogram" relationships. We still + // them and they lose their "pseudo-parallelogram" relationships. We still // have to do the normalization divisions and min/max all 4 points to // get the resulting transformed bounding box, but we save a lot of // calculations over blindly transforming all 4 coordinates independently. @@ -344,8 +344,8 @@ class MatrixUtils { // for a total of 8 multiplies, 8 adds, and 4 comparisons. // // An astute observer will note that we do need to do 2 subtractions at - // the top of the method to compute the width and height. Add those to - // all of the relative solutions listed above. The test for perspective + // the top of the method to compute the width and height. Add those to + // all of the relative solutions listed above. The test for perspective // also adds 3 compares to the affine case and up to 3 compares to the // perspective case (depending on which test fails, the rest are omitted). // diff --git a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart index fd8ef67ceccde..2e2faf8daa2f4 100644 --- a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart @@ -10,7 +10,6 @@ import 'basic_types.dart'; import 'border_radius.dart'; import 'borders.dart'; import 'circle_border.dart'; -import 'edge_insets.dart'; /// A rectangular border with rounded corners. /// @@ -37,18 +36,6 @@ class RoundedRectangleBorder extends OutlinedBorder { /// The radii for each corner. final BorderRadiusGeometry borderRadius; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) { return RoundedRectangleBorder( @@ -110,18 +97,7 @@ class RoundedRectangleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect; - break; - } + final RRect adjustedRect = borderRect.deflate(side.strokeInset); return Path() ..addRRect(adjustedRect); } @@ -150,30 +126,17 @@ class RoundedRectangleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final double width = side.width; - if (width == 0.0) { + if (side.width == 0.0) { canvas.drawRRect(borderRadius.resolve(textDirection).toRRect(rect), side.toPaint()); } else { final Paint paint = Paint() ..color = side.color; - if (side.strokeAlign == StrokeAlign.inside) { - final RRect outer = borderRadius.resolve(textDirection).toRRect(rect); - final RRect inner = outer.deflate(width); - canvas.drawDRRect(outer, inner, paint); - } else { - final Rect inner; - final Rect outer; - if (side.strokeAlign == StrokeAlign.center) { - inner = rect.deflate(width / 2); - outer = rect.inflate(width / 2); - } else { - inner = rect; - outer = rect.inflate(width); - } - final BorderRadius borderRadiusResolved = borderRadius.resolve(textDirection); - canvas.drawDRRect(borderRadiusResolved.toRRect(outer), borderRadiusResolved.toRRect(inner), paint); + final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect); + final RRect inner = borderRect.deflate(side.strokeInset); + final RRect outer = borderRect.inflate(side.strokeOutset); + canvas.drawDRRect(outer, inner, paint); } - } + break; } } @@ -210,18 +173,6 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { final double circleness; final double eccentricity; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) { return _RoundedRectangleToCircleBorder( @@ -342,18 +293,7 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { final RRect borderRect = _adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect)); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect; - break; - } + final RRect adjustedRect = borderRect.deflate(ui.lerpDouble(side.width, 0, side.strokeAlign)!); return Path() ..addRRect(adjustedRect); } @@ -393,25 +333,9 @@ class _RoundedRectangleToCircleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final double width = side.width; - if (width == 0.0) { - canvas.drawRRect(_adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect)), side.toPaint()); - } else { - final RRect borderRect = _adjustBorderRadius(rect, textDirection)!.toRRect(_adjustRect(rect)); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(width / 2); - break; - case StrokeAlign.center: - adjustedRect = borderRect; - break; - case StrokeAlign.outside: - adjustedRect = borderRect.inflate(width / 2); - break; - } - canvas.drawRRect(adjustedRect, side.toPaint()); - } + final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect, textDirection)!; + final RRect borderRect = adjustedBorderRadius.toRRect(_adjustRect(rect)); + canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } } diff --git a/packages/flutter/lib/src/painting/stadium_border.dart b/packages/flutter/lib/src/painting/stadium_border.dart index 22317e580b056..b7a0d7677b121 100644 --- a/packages/flutter/lib/src/painting/stadium_border.dart +++ b/packages/flutter/lib/src/painting/stadium_border.dart @@ -10,7 +10,6 @@ import 'basic_types.dart'; import 'border_radius.dart'; import 'borders.dart'; import 'circle_border.dart'; -import 'edge_insets.dart'; import 'rounded_rectangle_border.dart'; /// A border that fits a stadium-shaped border (a box with semicircles on the ends) @@ -30,18 +29,6 @@ class StadiumBorder extends OutlinedBorder { /// The [side] argument must not be null. const StadiumBorder({ super.side }) : assert(side != null); - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) => StadiumBorder(side: side.scale(t)); @@ -100,18 +87,7 @@ class StadiumBorder extends OutlinedBorder { Path getInnerPath(Rect rect, { TextDirection? textDirection }) { final Radius radius = Radius.circular(rect.shortestSide / 2.0); final RRect borderRect = RRect.fromRectAndRadius(rect, radius); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect; - break; - } + final RRect adjustedRect = borderRect.deflate(side.strokeInset); return Path() ..addRRect(adjustedRect); } @@ -140,22 +116,7 @@ class StadiumBorder extends OutlinedBorder { case BorderStyle.solid: final Radius radius = Radius.circular(rect.shortestSide / 2); final RRect borderRect = RRect.fromRectAndRadius(rect, radius); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.center: - adjustedRect = borderRect; - break; - case StrokeAlign.outside: - adjustedRect = borderRect.inflate(side.width / 2); - break; - } - canvas.drawRRect( - adjustedRect, - side.toPaint(), - ); + canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } } @@ -189,18 +150,6 @@ class _StadiumToCircleBorder extends OutlinedBorder { final double circleness; final double eccentricity; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) { return _StadiumToCircleBorder( @@ -312,7 +261,7 @@ class _StadiumToCircleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { return Path() - ..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.width)); + ..addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.strokeInset)); } @override @@ -344,25 +293,8 @@ class _StadiumToCircleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final double width = side.width; - if (width == 0.0) { - canvas.drawRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)), side.toPaint()); - } else { - final RRect borderRect = _adjustBorderRadius(rect).toRRect(_adjustRect(rect)); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(width / 2); - break; - case StrokeAlign.center: - adjustedRect = borderRect; - break; - case StrokeAlign.outside: - adjustedRect = borderRect.inflate(width / 2); - break; - } - canvas.drawRRect(adjustedRect, side.toPaint()); - } + final RRect borderRect = _adjustBorderRadius(rect).toRRect(_adjustRect(rect)); + canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } } @@ -402,11 +334,6 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { final double rectness; - @override - EdgeInsetsGeometry get dimensions { - return EdgeInsets.all(side.width); - } - @override ShapeBorder scale(double t) { return _StadiumToRoundedRectangleBorder( @@ -481,18 +408,7 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, { TextDirection? textDirection }) { final RRect borderRect = _adjustBorderRadius(rect).toRRect(rect); - final RRect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = borderRect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = borderRect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = borderRect; - break; - } + final RRect adjustedRect = borderRect.deflate(ui.lerpDouble(side.width, 0, side.strokeAlign)!); return Path() ..addRRect(adjustedRect); } @@ -531,26 +447,9 @@ class _StadiumToRoundedRectangleBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final double width = side.width; - if (width == 0.0) { - canvas.drawRRect(_adjustBorderRadius(rect).toRRect(rect), side.toPaint()); - } else { - if (side.strokeAlign == StrokeAlign.inside) { - final RRect outer = _adjustBorderRadius(rect).toRRect(rect); - final RRect inner = outer.deflate(width); - final Paint paint = Paint() - ..color = side.color; - canvas.drawDRRect(outer, inner, paint); - } else { - final RRect outer; - if (side.strokeAlign == StrokeAlign.center) { - outer = _adjustBorderRadius(rect).toRRect(rect); - } else { - outer = _adjustBorderRadius(rect.inflate(width)).toRRect(rect.inflate(width / 2)); - } - canvas.drawRRect(outer, side.toPaint()); - } - } + final BorderRadius adjustedBorderRadius = _adjustBorderRadius(rect); + final RRect borderRect = adjustedBorderRadius.resolve(textDirection).toRRect(rect); + canvas.drawRRect(borderRect.inflate(side.strokeOffset / 2), side.toPaint()); } } diff --git a/packages/flutter/lib/src/painting/star_border.dart b/packages/flutter/lib/src/painting/star_border.dart index 7e51a13a11709..177aefd395381 100644 --- a/packages/flutter/lib/src/painting/star_border.dart +++ b/packages/flutter/lib/src/painting/star_border.dart @@ -11,7 +11,6 @@ import 'package:vector_math/vector_math_64.dart' show Matrix4; import 'basic_types.dart'; import 'borders.dart'; import 'circle_border.dart'; -import 'edge_insets.dart'; import 'rounded_rectangle_border.dart'; import 'stadium_border.dart'; @@ -166,18 +165,6 @@ class StarBorder extends OutlinedBorder { /// Defaults to zero, and must be between zero and one, inclusive. final double squash; - @override - EdgeInsetsGeometry get dimensions { - switch (side.strokeAlign) { - case StrokeAlign.inside: - return EdgeInsets.all(side.width); - case StrokeAlign.center: - return EdgeInsets.all(side.width / 2); - case StrokeAlign.outside: - return EdgeInsets.zero; - } - } - @override ShapeBorder scale(double t) { return StarBorder( @@ -388,18 +375,7 @@ class StarBorder extends OutlinedBorder { @override Path getInnerPath(Rect rect, {TextDirection? textDirection}) { - final Rect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = rect.deflate(side.width); - break; - case StrokeAlign.center: - adjustedRect = rect.deflate(side.width / 2); - break; - case StrokeAlign.outside: - adjustedRect = rect; - break; - } + final Rect adjustedRect = rect.deflate(side.strokeInset); return _StarGenerator( points: points, rotation: _rotationRadians, @@ -428,18 +404,7 @@ class StarBorder extends OutlinedBorder { case BorderStyle.none: break; case BorderStyle.solid: - final Rect adjustedRect; - switch (side.strokeAlign) { - case StrokeAlign.inside: - adjustedRect = rect.deflate(side.width / 2); - break; - case StrokeAlign.center: - adjustedRect = rect; - break; - case StrokeAlign.outside: - adjustedRect = rect.inflate(side.width / 2); - break; - } + final Rect adjustedRect = rect.inflate(side.strokeOffset / 2); final Path path = _StarGenerator( points: points, rotation: _rotationRadians, @@ -549,7 +514,6 @@ class _StarGenerator { } else { scale = Offset(squash * scale.dx + (1 - squash) * scale.dy, scale.dy); } - // Scale the border so that it matches the size of the widget rectangle, so // that "rotation" of the shape doesn't affect how much of the rectangle it // covers. @@ -645,10 +609,12 @@ class _StarGenerator { } // The rounding added to the valley radius can sometimes push it outside of - // the rounding of the point, since the rounding amount can be different, so - // we have to evaluate both the valley and the point radii, and pick the - // largest. - return math.max(valleyRadius, pointRadius); + // the rounding of the point, since the rounding amount can be different + // between the points and the valleys, so we have to evaluate both the + // valley and the point radii, and pick the largest. Also, since this value + // is used later to determine the scale, we need to keep it finite and + // non-zero. + return clampDouble(math.max(valleyRadius, pointRadius), double.minPositive, double.maxFinite); } void _drawPoints(Path path, List<_PointInfo> points) { diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart index 0301f8d6f6a1d..81cc9f07be365 100644 --- a/packages/flutter/lib/src/painting/text_style.dart +++ b/packages/flutter/lib/src/painting/text_style.dart @@ -772,16 +772,16 @@ class TextStyle with Diagnosticable { /// A list of [FontFeature]s that affect how the font selects glyphs. /// /// Some fonts support multiple variants of how a given character can be - /// rendered. For example, a font might provide both proportional and + /// rendered. For example, a font might provide both proportional and /// tabular numbers, or it might offer versions of the zero digit with - /// and without slashes. [FontFeature]s can be used to select which of + /// and without slashes. [FontFeature]s can be used to select which of /// these variants will be used for rendering. final List? fontFeatures; /// A list of [FontVariation]s that affect how a variable font is rendered. /// /// Some fonts are variable fonts that can generate multiple font faces based - /// on the values of customizable attributes. For example, a variable font + /// on the values of customizable attributes. For example, a variable font /// may have a weight axis that can be set to a value between 1 and 1000. /// [FontVariation]s can be used to select the values of these design axes. /// diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index a81353af2287d..7efe503b67320 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -2191,8 +2191,12 @@ abstract class RenderBox extends RenderObject { return false; }()); assert(_debugSetDoingBaseline(true)); - final double? result = getDistanceToActualBaseline(baseline); - assert(_debugSetDoingBaseline(false)); + final double? result; + try { + result = getDistanceToActualBaseline(baseline); + } finally { + assert(_debugSetDoingBaseline(false)); + } if (result == null && !onlyReal) { return size.height; } diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index 0e1965f22a29e..34626293766b9 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -887,12 +887,6 @@ class TextureLayer extends Layer { /// The identity of the backend texture. final int textureId; - // TODO(jonahwilliams): remove once https://github.com/flutter/flutter/issues/107576 is fixed. - @override - bool supportsRasterization() { - return false; - } - /// When true the texture will not be updated with new frames. /// /// This is used for resizing embedded Android views: when resizing there diff --git a/packages/flutter/lib/src/rendering/mouse_tracker.dart b/packages/flutter/lib/src/rendering/mouse_tracker.dart index 0e4ccc9f44b81..9b9af0fa69559 100644 --- a/packages/flutter/lib/src/rendering/mouse_tracker.dart +++ b/packages/flutter/lib/src/rendering/mouse_tracker.dart @@ -297,7 +297,7 @@ class MouseTracker extends ChangeNotifier { /// result. /// /// The [updateWithEvent] indicates that an event has been observed, and is - /// called during the handler of the event. It is typically called by + /// called during the handler of the event. It is typically called by /// [RendererBinding], and should be called with all events received, and let /// [MouseTracker] filter which to react to. /// diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart index 1dcabf4fadaac..b1700fc6f832d 100644 --- a/packages/flutter/lib/src/rendering/platform_view.dart +++ b/packages/flutter/lib/src/rendering/platform_view.dart @@ -732,7 +732,7 @@ mixin _PlatformViewGestureMixin on RenderBox implements MouseTrackerAnnotation { _HandlePointerEvent? _handlePointerEvent; - /// {@macro flutter.rendering.RenderAndroidView.updateGestureRecognizers} + /// {@macro flutter.rendering.RenderAndroidView.updateGestureRecognizers} /// /// Any active gesture arena the `PlatformView` participates in is rejected when the /// set of gesture recognizers is changed. diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart index 3c257c4df7b9e..6366872219313 100644 --- a/packages/flutter/lib/src/rendering/shifted_box.dart +++ b/packages/flutter/lib/src/rendering/shifted_box.dart @@ -656,9 +656,9 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox { } } -/// A [RenderBox] that applies an arbitrary transform to its [constraints] -/// before sizing its child using the new constraints, treating any overflow as -/// error. +/// A [RenderBox] that applies an arbitrary transform to its constraints, +/// and sizes its child using the resulting [BoxConstraints], optionally +/// clipping, or treating the overflow as an error. /// /// This [RenderBox] sizes its child using a [BoxConstraints] created by /// applying [constraintsTransform] to this [RenderBox]'s own [constraints]. @@ -668,9 +668,9 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox { /// the entire child, the child will be clipped if [clipBehavior] is not /// [Clip.none]. /// -/// In debug mode, if the child overflows the box, a warning will be printed on -/// the console, and black and yellow striped areas will appear where the -/// overflow occurs. +/// In debug mode, if [clipBehavior] is [Clip.none] and the child overflows the +/// container, a warning will be printed on the console, and black and yellow +/// striped areas will appear where the overflow occurs. /// /// When [child] is null, this [RenderBox] takes the smallest possible size and /// never overflows. @@ -732,7 +732,9 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// {@macro flutter.widgets.ConstraintsTransformBox.clipBehavior} + /// + /// Defaults to [Clip.none]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior; set clipBehavior(Clip value) { @@ -830,9 +832,17 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO oldLayer: _clipRectLayer.layer, ); - // Display the overflow indicator. + // Display the overflow indicator if clipBehavior is Clip.none. assert(() { - paintOverflowIndicator(context, offset, _overflowContainerRect, _overflowChildRect); + switch (clipBehavior) { + case Clip.none: + paintOverflowIndicator(context, offset, _overflowContainerRect, _overflowChildRect); + break; + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + break; + } return true; }()); } diff --git a/packages/flutter/lib/src/services/hardware_keyboard.dart b/packages/flutter/lib/src/services/hardware_keyboard.dart index aabc0828cd1d8..224b12074dc37 100644 --- a/packages/flutter/lib/src/services/hardware_keyboard.dart +++ b/packages/flutter/lib/src/services/hardware_keyboard.dart @@ -353,7 +353,7 @@ typedef KeyEventCallback = bool Function(KeyEvent event); /// ## Compared to [RawKeyboard] /// /// [RawKeyboard] is the legacy API, and will be deprecated and removed in the -/// future. It is recommended to always use [HardwareKeyboard] and [KeyEvent] +/// future. It is recommended to always use [HardwareKeyboard] and [KeyEvent] /// APIs (such as [FocusNode.onKeyEvent]) to handle key events. /// /// Behavior-wise, [RawKeyboard] provides a less unified, less regular @@ -672,7 +672,7 @@ class KeyMessage { /// The list of [KeyEvent]s converted from the native key message. /// /// A native key message is converted into multiple [KeyEvent]s in a regular - /// event model. The [events] might contain zero or any number of + /// event model. The [events] might contain zero or any number of /// [KeyEvent]s. /// /// See also: diff --git a/packages/flutter/lib/src/services/raw_keyboard.dart b/packages/flutter/lib/src/services/raw_keyboard.dart index 937081e82de5f..b3571bb875925 100644 --- a/packages/flutter/lib/src/services/raw_keyboard.dart +++ b/packages/flutter/lib/src/services/raw_keyboard.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'binding.dart'; @@ -88,7 +89,7 @@ enum ModifierKey { /// The SCROLL LOCK modifier key. /// - /// Typically, there is one of these. Only shown as "pressed" when the scroll + /// Typically, there is one of these. Only shown as "pressed" when the scroll /// lock is on, so on a key up when the mode is turned on, on each key press /// when it's enabled, and on a key down when it is turned off. scrollLockModifier, @@ -568,7 +569,7 @@ class RawKeyUpEvent extends RawKeyEvent { /// a handler that can determine if the key has been handled or not. /// /// The handler should return true if the key has been handled, and false if the -/// key was not handled. It must not return null. +/// key was not handled. It must not return null. typedef RawKeyEventHandler = bool Function(RawKeyEvent event); /// An interface for listening to raw key events. diff --git a/packages/flutter/lib/src/services/text_editing.dart b/packages/flutter/lib/src/services/text_editing.dart index 39c8caeb80de1..6dae30a85f15f 100644 --- a/packages/flutter/lib/src/services/text_editing.dart +++ b/packages/flutter/lib/src/services/text_editing.dart @@ -199,7 +199,7 @@ class TextSelection extends TextRange { /// ## Difference with [extendTo] /// In contrast with this method, [extendTo] is a pivot; it holds /// [TextSelection.baseOffset] fixed while moving [TextSelection.extentOffset] - /// to the given [TextPosition]. It doesn't strictly grow the selection and + /// to the given [TextPosition]. It doesn't strictly grow the selection and /// may collapse it or flip its order. TextSelection expandTo(TextPosition position, [bool extentAtIndex = false]) { // If position is already within in the selection, there's nothing to do. diff --git a/packages/flutter/lib/src/widgets/actions.dart b/packages/flutter/lib/src/widgets/actions.dart index e3484068619bd..ae7158242290d 100644 --- a/packages/flutter/lib/src/widgets/actions.dart +++ b/packages/flutter/lib/src/widgets/actions.dart @@ -145,12 +145,16 @@ abstract class Action with Diagnosticable { /// parent widgets that also support this [Intent]. /// /// {@tool dartpad} - /// This sample implements a custom text input field that handles the - /// [DeleteCharacterIntent] intent, as well as a US telephone number input - /// widget that consists of multiple text fields for area code, prefix and line - /// number. When the backspace key is pressed, the phone number input widget - /// sends the focus to the preceding text field when the currently focused - /// field becomes empty. + /// This sample shows how to implement a rudimentary `CopyableText` widget + /// that responds to Ctrl-C by copying its own content to the clipboard. + /// + /// if `CopyableText` is to be provided in a package, developers using the + /// widget may want to change how copying is handled. As the author of the + /// package, you can enable that by making the corresponding [Action] + /// overridable. In the second part of the code sample, three `CopyableText` + /// widgets are used to build a verification code widget which overrides the + /// "copy" action by copying the combined numbers from all three `CopyableText` + /// widgets. /// /// ** See code in examples/api/lib/widgets/actions/action.action_overridable.0.dart ** /// {@end-tool} diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 93f8c455f42c9..5aac7565d457c 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -13,6 +13,7 @@ import 'banner.dart'; import 'basic.dart'; import 'binding.dart'; import 'default_text_editing_shortcuts.dart'; +import 'focus_scope.dart'; import 'focus_traversal.dart'; import 'framework.dart'; import 'localizations.dart'; @@ -277,7 +278,7 @@ class WidgetsApp extends StatefulWidget { /// ``` /// /// It is possible to specify both [home] and [routes], but only if [routes] does - /// _not_ contain an entry for `'/'`. Conversely, if [home] is omitted, [routes] + /// _not_ contain an entry for `'/'`. Conversely, if [home] is omitted, [routes] /// _must_ contain an entry for `'/'`. /// /// If [home] or [routes] are not null, the routing implementation needs to know how @@ -294,7 +295,7 @@ class WidgetsApp extends StatefulWidget { /// [onGenerateRoute] and [onUnknownRoute] parameters. These parameters correspond /// to [Navigator.onGenerateRoute] and [Navigator.onUnknownRoute]. If [home], [routes], /// and [builder] are null, or if they fail to create a requested route, - /// [onGenerateRoute] will be invoked. If that fails, [onUnknownRoute] will be invoked. + /// [onGenerateRoute] will be invoked. If that fails, [onUnknownRoute] will be invoked. /// /// The [pageRouteBuilder] is called to create a [PageRoute] that wraps newly built routes. /// If the [builder] is non-null and the [onGenerateRoute] argument is null, then the @@ -1625,19 +1626,23 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { ); } else if (_usesNavigator) { assert(_navigator != null); - routing = Navigator( - restorationScopeId: 'nav', - key: _navigator, - initialRoute: _initialRouteName, - onGenerateRoute: _onGenerateRoute, - onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null - ? Navigator.defaultGenerateInitialRoutes - : (NavigatorState navigator, String initialRouteName) { - return widget.onGenerateInitialRoutes!(initialRouteName); - }, - onUnknownRoute: _onUnknownRoute, - observers: widget.navigatorObservers!, - reportsRouteUpdateToEngine: true, + routing = FocusScope( + debugLabel: 'Navigator Scope', + autofocus: true, + child: Navigator( + restorationScopeId: 'nav', + key: _navigator, + initialRoute: _initialRouteName, + onGenerateRoute: _onGenerateRoute, + onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null + ? Navigator.defaultGenerateInitialRoutes + : (NavigatorState navigator, String initialRouteName) { + return widget.onGenerateInitialRoutes!(initialRouteName); + }, + onUnknownRoute: _onUnknownRoute, + observers: widget.navigatorObservers!, + reportsRouteUpdateToEngine: true, + ), ); } else if (_usesRouterWithConfig) { routing = Router.withConfig( diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index 22760222d2043..4e4bd957211c7 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -438,7 +438,7 @@ class _RawAutocompleteState extends State> ); }, ); - Overlay.of(context, rootOverlay: true, debugRequiredFor: widget)!.insert(newFloatingOptions); + Overlay.of(context, rootOverlay: true, debugRequiredFor: widget).insert(newFloatingOptions); _floatingOptions = newFloatingOptions; } else { _floatingOptions = null; diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 1406bc6bd34b0..037dc2347d00e 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -82,7 +82,7 @@ export 'package:flutter/services.dart' show // BIDIRECTIONAL TEXT SUPPORT /// An [InheritedElement] that has hundreds of dependencies but will -/// infrequently change. This provides a performance tradeoff where building +/// infrequently change. This provides a performance tradeoff where building /// the [Widget]s is faster but performing updates is slower. /// /// | | _UbiquitiousInheritedElement | InheritedElement | @@ -101,7 +101,7 @@ class _UbiquitousInheritedElement extends InheritedElement { @override void setDependencies(Element dependent, Object? value) { // This is where the cost of [InheritedElement] is incurred during build - // time of the widget tree. Omitting this bookkeeping is where the + // time of the widget tree. Omitting this bookkeeping is where the // performance savings come from. assert(value == null); } @@ -2513,8 +2513,8 @@ class ConstrainedBox extends SingleChildRenderObjectWidget { } /// A container widget that applies an arbitrary transform to its constraints, -/// and sizes its child using the resulting [BoxConstraints], treating any -/// overflow as error. +/// and sizes its child using the resulting [BoxConstraints], optionally +/// clipping, or treating the overflow as an error. /// /// This container sizes its child using a [BoxConstraints] created by applying /// [constraintsTransform] to its own constraints. This container will then @@ -2523,12 +2523,12 @@ class ConstrainedBox extends SingleChildRenderObjectWidget { /// [alignment]. If the container cannot expand enough to accommodate the entire /// child, the child will be clipped if [clipBehavior] is not [Clip.none]. /// -/// In debug mode, if the child overflows the container, a warning will be -/// printed on the console, and black and yellow striped areas will appear where -/// the overflow occurs. +/// In debug mode, if [clipBehavior] is [Clip.none] and the child overflows the +/// container, a warning will be printed on the console, and black and yellow +/// striped areas will appear where the overflow occurs. /// /// When [child] is null, this widget becomes as small as possible and never -/// overflows +/// overflows. /// /// This widget can be used to ensure some of [child]'s natural dimensions are /// honored, and get an early warning otherwise during development. For @@ -2564,7 +2564,7 @@ class ConstrainedBox extends SingleChildRenderObjectWidget { /// * [OverflowBox], a widget that imposes additional constraints on its child, /// and allows the child to overflow itself. /// * [UnconstrainedBox] which allows its children to render themselves -/// unconstrained, expands to fit them, and considers overflow to be an error. +/// unconstrained and expands to fit them. class ConstraintsTransformBox extends SingleChildRenderObjectWidget { /// Creates a widget that uses a function to transform the constraints it /// passes to its child. If the child overflows the parent's constraints, a @@ -2686,6 +2686,13 @@ class ConstraintsTransformBox extends SingleChildRenderObjectWidget { /// {@macro flutter.material.Material.clipBehavior} /// + /// {@template flutter.widgets.ConstraintsTransformBox.clipBehavior} + /// In debug mode, if `clipBehavior` is [Clip.none], and the child overflows + /// its constraints, a warning will be printed on the console, and black and + /// yellow striped areas will appear where the overflow occurs. For other + /// values of `clipBehavior`, the contents are clipped accordingly. + /// {@endtemplate} + /// /// Defaults to [Clip.none]. final Clip clipBehavior; @@ -3404,7 +3411,7 @@ class IntrinsicWidth extends SingleChildRenderObjectWidget { /// See also: /// /// * [RenderBox.getMaxIntrinsicWidth], which defines a widget's max - /// intrinsic width in general. + /// intrinsic width in general. final double? stepWidth; /// If non-null, force the child's height to be a multiple of this value. diff --git a/packages/flutter/lib/src/widgets/container.dart b/packages/flutter/lib/src/widgets/container.dart index f157fa5ce9af2..c5e80a4ab6adb 100644 --- a/packages/flutter/lib/src/widgets/container.dart +++ b/packages/flutter/lib/src/widgets/container.dart @@ -216,7 +216,7 @@ class DecoratedBox extends SingleChildRenderObjectWidget { /// ```dart /// Container( /// constraints: BoxConstraints.expand( -/// height: Theme.of(context).textTheme.headline4!.fontSize! * 1.1 + 200.0, +/// height: Theme.of(context).textTheme.headlineMedium!.fontSize! * 1.1 + 200.0, /// ), /// padding: const EdgeInsets.all(8.0), /// color: Colors.blue[600], @@ -225,7 +225,7 @@ class DecoratedBox extends SingleChildRenderObjectWidget { /// child: Text('Hello World', /// style: Theme.of(context) /// .textTheme -/// .headline4! +/// .headlineMedium! /// .copyWith(color: Colors.white)), /// ) /// ``` diff --git a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart index 0ad4c04371689..11b6fc95e8bc5 100644 --- a/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart +++ b/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart @@ -94,7 +94,7 @@ import 'text_editing_intents.dart'; /// ), /// Text( /// '$_counter', -/// style: Theme.of(context).textTheme.headline4, +/// style: Theme.of(context).textTheme.headlineMedium, /// ), /// Shortcuts( /// shortcuts: { @@ -258,32 +258,7 @@ class DefaultTextEditingShortcuts extends StatelessWidget { // macOS document shortcuts: https://support.apple.com/en-us/HT201236. // The macOS shortcuts uses different word/line modifiers than most other // platforms. - static final Map _macShortcuts = { - const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const CopySelectionTextIntent.cut(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyC, meta: true): CopySelectionTextIntent.copy, - const SingleActivator(LogicalKeyboardKey.keyV, meta: true): const PasteTextIntent(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const SelectAllTextIntent(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyZ, meta: true): const UndoTextIntent(SelectionChangedCause.keyboard), - const SingleActivator(LogicalKeyboardKey.keyZ, shift: true, meta: true): const RedoTextIntent(SelectionChangedCause.keyboard), - - // On desktop these keys should go to the IME when a field is focused, not to other - // Shortcuts. - if (!kIsWeb) ...{ - const SingleActivator(LogicalKeyboardKey.arrowLeft): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.escape): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.enter): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.tab): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.tab, shift: true): const DoNothingAndStopPropagationTextIntent(), - }, - }; + static final Map _macShortcuts = _iOSShortcuts; // There is no complete documentation of iOS shortcuts. static final Map _iOSShortcuts = { @@ -399,42 +374,7 @@ class DefaultTextEditingShortcuts extends StatelessWidget { SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), SingleActivator(LogicalKeyboardKey.delete, meta: true, shift: pressShift): const DoNothingAndStopPropagationTextIntent(), }, - const SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home, shift: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.end, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.home, control: true): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.space): const DoNothingAndStopPropagationTextIntent(), - const SingleActivator(LogicalKeyboardKey.enter): const DoNothingAndStopPropagationTextIntent(), + ..._commonDisablingTextShortcuts, const SingleActivator(LogicalKeyboardKey.keyX, control: true): const DoNothingAndStopPropagationTextIntent(), const SingleActivator(LogicalKeyboardKey.keyX, meta: true): const DoNothingAndStopPropagationTextIntent(), const SingleActivator(LogicalKeyboardKey.keyC, control: true): const DoNothingAndStopPropagationTextIntent(), @@ -445,6 +385,53 @@ class DefaultTextEditingShortcuts extends StatelessWidget { const SingleActivator(LogicalKeyboardKey.keyA, meta: true): const DoNothingAndStopPropagationTextIntent(), }; + + static const Map _commonDisablingTextShortcuts = { + SingleActivator(LogicalKeyboardKey.arrowDown, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, alt: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, meta: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.end, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.home, shift: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.end): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.home): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.end, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.home, control: true): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.space): DoNothingAndStopPropagationTextIntent(), + SingleActivator(LogicalKeyboardKey.enter): DoNothingAndStopPropagationTextIntent(), + }; + + static final Map _macDisablingTextShortcuts = { + ..._commonDisablingTextShortcuts, + const SingleActivator(LogicalKeyboardKey.escape): const DoNothingAndStopPropagationTextIntent(), + const SingleActivator(LogicalKeyboardKey.tab): const DoNothingAndStopPropagationTextIntent(), + const SingleActivator(LogicalKeyboardKey.tab, shift: true): const DoNothingAndStopPropagationTextIntent(), + }; + static Map get _shortcuts { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -462,21 +449,39 @@ class DefaultTextEditingShortcuts extends StatelessWidget { } } + Map? _getDisablingShortcut() { + if (kIsWeb) { + return _webDisablingTextShortcuts; + } + switch (defaultTargetPlatform) { + + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + case TargetPlatform.linux: + case TargetPlatform.windows: + return null; + case TargetPlatform.macOS: + return _macDisablingTextShortcuts; + } + } + @override Widget build(BuildContext context) { Widget result = child; - if (kIsWeb) { - // On the web, these shortcuts make sure of the following: + final Map? disablingShortcut = _getDisablingShortcut(); + if (disablingShortcut != null) { + // These shortcuts make sure of the following: // // 1. Shortcuts fired when an EditableText is focused are ignored and - // forwarded to the browser by the EditableText's Actions, because it + // forwarded to the platform by the EditableText's Actions, because it // maps DoNothingAndStopPropagationTextIntent to DoNothingAction. // 2. Shortcuts fired when no EditableText is focused will still trigger // _shortcuts assuming DoNothingAndStopPropagationTextIntent is // unhandled elsewhere. result = Shortcuts( debugLabel: '', - shortcuts: _webDisablingTextShortcuts, + shortcuts: disablingShortcut, child: result ); } diff --git a/packages/flutter/lib/src/widgets/dismissible.dart b/packages/flutter/lib/src/widgets/dismissible.dart index 5e4f02defc75c..08f28c4acb805 100644 --- a/packages/flutter/lib/src/widgets/dismissible.dart +++ b/packages/flutter/lib/src/widgets/dismissible.dart @@ -323,6 +323,8 @@ class _DismissibleState extends State with TickerProviderStateMixin Size? _sizePriorToCollapse; bool _dismissThresholdReached = false; + final GlobalKey _contentKey = GlobalKey(); + @override bool get wantKeepAlive => (_moveController?.isAnimating ?? false) || (_resizeController?.isAnimating ?? false); @@ -668,7 +670,7 @@ class _DismissibleState extends State with TickerProviderStateMixin Widget content = SlideTransition( position: _moveAnimation, - child: widget.child, + child: KeyedSubtree(key: _contentKey, child: widget.child), ); if (background != null) { diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index 17a685960dcea..40ddc58e1ba03 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -311,7 +311,7 @@ class Draggable extends StatefulWidget { /// the semantics tree. /// /// This value should be set to false when the [feedback] widget is intended - /// to be the same object as the [child]. Placing a [GlobalKey] on this + /// to be the same object as the [child]. Placing a [GlobalKey] on this /// widget will ensure semantic focus is kept on the element as it moves in /// and out of the feedback position. /// @@ -555,7 +555,7 @@ class _DraggableState extends State> { _activeCount += 1; }); final _DragAvatar avatar = _DragAvatar( - overlayState: Overlay.of(context, debugRequiredFor: widget, rootOverlay: widget.rootOverlay)!, + overlayState: Overlay.of(context, debugRequiredFor: widget, rootOverlay: widget.rootOverlay), data: widget.data, axis: widget.axis, initialPosition: position, diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 303589565942b..0a6e647228e38 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -424,8 +424,8 @@ class DraggableScrollableNotification extends Notification with ViewportNotifica /// Creates a notification that the extent of a [DraggableScrollableSheet] has /// changed. /// - /// All parameters are required. The [minExtent] must be >= 0. The [maxExtent] - /// must be <= 1.0. The [extent] must be between [minExtent] and [maxExtent]. + /// All parameters are required. The [minExtent] must be >= 0. The [maxExtent] + /// must be <= 1.0. The [extent] must be between [minExtent] and [maxExtent]. DraggableScrollableNotification({ required this.extent, required this.minExtent, diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index de40b05f26a69..8fa7f9fca9a7e 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -478,12 +478,12 @@ class _DiscreteKeyFrameSimulation extends Simulation { /// /// | **Intent Class** | **Default Behavior when there's selected text** | **Default Behavior when there is a caret ([TextSelection.collapsed])** | /// | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------- | -/// | [ExtendSelectionByCharacterIntent](`collapseSelection: true`) | Collapses the selection to the logical start/end of the selection | Moves the caret past the user-perceived character before or after the current caret location. | -/// | [ExtendSelectionToNextWordBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position | Moves the caret to the previous/next word boundary. | -/// | [ExtendSelectionToNextWordBoundaryOrCaretLocationIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position, or [TextSelection.base], whichever is closest in the given direction | Moves the caret to the previous/next word boundary. | -/// | [ExtendSelectionToLineBreakIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the line at the selection's [TextSelection.extent] position | Moves the caret to the start/end of the current line .| -/// | [ExtendSelectionVerticallyToAdjacentLineIntent](`collapseSelection: true`) | Collapses the selection to the position closest to the selection's [TextSelection.extent], on the previous/next adjacent line | Moves the caret to the closest position on the previous/next adjacent line. | -/// | [ExtendSelectionToDocumentBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the document | Moves the caret to the start/end of the document. | +/// | [ExtendSelectionByCharacterIntent](`collapseSelection: true`) | Collapses the selection to the logical start/end of the selection | Moves the caret past the user-perceived character before or after the current caret location. | +/// | [ExtendSelectionToNextWordBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position | Moves the caret to the previous/next word boundary. | +/// | [ExtendSelectionToNextWordBoundaryOrCaretLocationIntent](`collapseSelection: true`) | Collapses the selection to the word boundary before/after the selection's [TextSelection.extent] position, or [TextSelection.base], whichever is closest in the given direction | Moves the caret to the previous/next word boundary. | +/// | [ExtendSelectionToLineBreakIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the line at the selection's [TextSelection.extent] position | Moves the caret to the start/end of the current line .| +/// | [ExtendSelectionVerticallyToAdjacentLineIntent](`collapseSelection: true`) | Collapses the selection to the position closest to the selection's [TextSelection.extent], on the previous/next adjacent line | Moves the caret to the closest position on the previous/next adjacent line. | +/// | [ExtendSelectionToDocumentBoundaryIntent](`collapseSelection: true`) | Collapses the selection to the start/end of the document | Moves the caret to the start/end of the document. | /// /// #### Intents for Extending the Selection /// @@ -3829,10 +3829,10 @@ class EditableTextState extends State with AutomaticKeepAliveClien final int placeholderLocation = _value.text.length - _placeholderLocation; if (_isMultiline) { // The zero size placeholder here allows the line to break and keep the caret on the first line. - placeholders.add(const _ScribblePlaceholder(child: SizedBox(), size: Size.zero)); - placeholders.add(_ScribblePlaceholder(child: const SizedBox(), size: Size(renderEditable.size.width, 0.0))); + placeholders.add(const _ScribblePlaceholder(child: SizedBox.shrink(), size: Size.zero)); + placeholders.add(_ScribblePlaceholder(child: const SizedBox.shrink(), size: Size(renderEditable.size.width, 0.0))); } else { - placeholders.add(const _ScribblePlaceholder(child: SizedBox(), size: Size(100.0, 0.0))); + placeholders.add(const _ScribblePlaceholder(child: SizedBox.shrink(), size: Size(100.0, 0.0))); } return TextSpan(style: widget.style, children: [ TextSpan(text: _value.text.substring(0, placeholderLocation)), diff --git a/packages/flutter/lib/src/widgets/fade_in_image.dart b/packages/flutter/lib/src/widgets/fade_in_image.dart index ec42f66011fce..e169bc9a0b4e3 100644 --- a/packages/flutter/lib/src/widgets/fade_in_image.dart +++ b/packages/flutter/lib/src/widgets/fade_in_image.dart @@ -65,9 +65,12 @@ class FadeInImage extends StatefulWidget { /// The [placeholder] and [image] may be composed in a [ResizeImage] to provide /// a custom decode/cache size. /// - /// The [placeholder] and [image] may be have their own BoxFit settings via [fit] + /// The [placeholder] and [image] may have their own BoxFit settings via [fit] /// and [placeholderFit]. /// + /// The [placeholder] and [image] may have their own FilterQuality settings via [filterQuality] + /// and [placeholderFilterQuality]. + /// /// The [placeholder], [image], [fadeOutDuration], [fadeOutCurve], /// [fadeInDuration], [fadeInCurve], [alignment], [repeat], and /// [matchTextDirection] arguments must not be null. @@ -89,6 +92,8 @@ class FadeInImage extends StatefulWidget { this.height, this.fit, this.placeholderFit, + this.filterQuality = FilterQuality.low, + this.placeholderFilterQuality, this.alignment = Alignment.center, this.repeat = ImageRepeat.noRepeat, this.matchTextDirection = false, @@ -148,6 +153,8 @@ class FadeInImage extends StatefulWidget { this.height, this.fit, this.placeholderFit, + this.filterQuality = FilterQuality.low, + this.placeholderFilterQuality, this.alignment = Alignment.center, this.repeat = ImageRepeat.noRepeat, this.matchTextDirection = false, @@ -219,6 +226,8 @@ class FadeInImage extends StatefulWidget { this.height, this.fit, this.placeholderFit, + this.filterQuality = FilterQuality.low, + this.placeholderFilterQuality, this.alignment = Alignment.center, this.repeat = ImageRepeat.noRepeat, this.matchTextDirection = false, @@ -301,6 +310,16 @@ class FadeInImage extends StatefulWidget { /// If not value set, it will fallback to [fit]. final BoxFit? placeholderFit; + /// The rendering quality of the image. + /// + /// {@macro flutter.widgets.image.filterQuality} + final FilterQuality filterQuality; + + /// The rendering quality of the placeholder image. + /// + /// {@macro flutter.widgets.image.filterQuality} + final FilterQuality? placeholderFilterQuality; + /// How to align the image within its bounds. /// /// The alignment aligns the given position in the image to the given position @@ -379,6 +398,7 @@ class _FadeInImageState extends State { ImageErrorWidgetBuilder? errorBuilder, ImageFrameBuilder? frameBuilder, BoxFit? fit, + required FilterQuality filterQuality, required Animation opacity, }) { assert(image != null); @@ -390,6 +410,7 @@ class _FadeInImageState extends State { width: widget.width, height: widget.height, fit: fit, + filterQuality: filterQuality, alignment: widget.alignment, repeat: widget.repeat, matchTextDirection: widget.matchTextDirection, @@ -405,6 +426,7 @@ class _FadeInImageState extends State { errorBuilder: widget.imageErrorBuilder, opacity: _imageAnimation, fit: widget.fit, + filterQuality: widget.filterQuality, frameBuilder: (BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded) { if (wasSynchronouslyLoaded || frame != null) { targetLoaded = true; @@ -417,6 +439,7 @@ class _FadeInImageState extends State { errorBuilder: widget.placeholderErrorBuilder, opacity: _placeholderAnimation, fit: widget.placeholderFit ?? widget.fit, + filterQuality: widget.placeholderFilterQuality ?? widget.filterQuality, ), placeholderProxyAnimation: _placeholderAnimation, isTargetLoaded: targetLoaded, diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 67c8d1728ea73..1da64cc6c9a89 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -452,7 +452,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// If true, this focus node may request the primary focus. /// - /// Defaults to true. Set to false if you want this node to do nothing when + /// Defaults to true. Set to false if you want this node to do nothing when /// [requestFocus] is called on it. /// /// If set to false on a [FocusScopeNode], will cause all of the children of @@ -1694,7 +1694,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { handled = false; break; } - // Only KeyEventResult.ignored will continue the for loop. All other + // Only KeyEventResult.ignored will continue the for loop. All other // options will stop the event propagation. assert(result != KeyEventResult.ignored); break; diff --git a/packages/flutter/lib/src/widgets/focus_scope.dart b/packages/flutter/lib/src/widgets/focus_scope.dart index eb3437cdfb9b2..4b858df4c6a3e 100644 --- a/packages/flutter/lib/src/widgets/focus_scope.dart +++ b/packages/flutter/lib/src/widgets/focus_scope.dart @@ -234,7 +234,7 @@ class Focus extends StatefulWidget { /// {@template flutter.widgets.Focus.canRequestFocus} /// If true, this widget may request the primary focus. /// - /// Defaults to true. Set to false if you want the [FocusNode] this widget + /// Defaults to true. Set to false if you want the [FocusNode] this widget /// manages to do nothing when [FocusNode.requestFocus] is called on it. Does /// not affect the children of this node, and [FocusNode.hasFocus] can still /// return true if this node is the ancestor of the primary focus. diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index e200ff8919fe9..a088fe2daad06 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1347,7 +1347,7 @@ class OrderedTraversalPolicy extends FocusTraversalPolicy with DirectionalFocusT a.order.runtimeType == b.order.runtimeType, 'When sorting nodes for determining focus order, the order (${a.order}) of ' "node ${a.node}, isn't the same type as the order (${b.order}) of ${b.node}. " - "Incompatible order types can't be compared. Use a FocusTraversalGroup to group " + "Incompatible order types can't be compared. Use a FocusTraversalGroup to group " 'similar orders together.', ); return a.order.compareTo(b.order); @@ -1442,7 +1442,7 @@ class FocusTraversalOrder extends InheritedWidget { /// {@tool dartpad} /// This sample shows three rows of buttons, each grouped by a /// [FocusTraversalGroup], each with different traversal order policies. Use tab -/// traversal to see the order they are traversed in. The first row follows a +/// traversal to see the order they are traversed in. The first row follows a /// numerical order, the second follows a lexical order (ordered to traverse /// right to left), and the third ignores the numerical order assigned to it and /// traverses in widget order. diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 16e59c475dea7..b78300494c533 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -870,6 +870,7 @@ class Image extends StatefulWidget { /// The rendering quality of the image. /// + /// {@template flutter.widgets.image.filterQuality} /// If the image is of a high quality and its pixels are perfectly aligned /// with the physical screen pixels, extra quality enhancement may not be /// necessary. If so, then [FilterQuality.none] would be the most efficient. @@ -884,6 +885,7 @@ class Image extends StatefulWidget { /// /// * [FilterQuality], the enum containing all possible filter quality /// options. + /// {@endtemplate} final FilterQuality filterQuality; /// Used to combine [color] with this image. @@ -1171,7 +1173,8 @@ class _ImageState extends State with WidgetsBindingObserver { } void _replaceImage({required ImageInfo? info}) { - _imageInfo?.dispose(); + final ImageInfo? oldImageInfo = _imageInfo; + SchedulerBinding.instance.addPostFrameCallback((_) => oldImageInfo?.dispose()); _imageInfo = info; } diff --git a/packages/flutter/lib/src/widgets/keyboard_listener.dart b/packages/flutter/lib/src/widgets/keyboard_listener.dart index 854d704b8c52d..86febcb819806 100644 --- a/packages/flutter/lib/src/widgets/keyboard_listener.dart +++ b/packages/flutter/lib/src/widgets/keyboard_listener.dart @@ -32,7 +32,7 @@ export 'package:flutter/services.dart' show KeyEvent; /// * [RawKeyboardListener], a similar widget based on the old [RawKeyboard] /// API. class KeyboardListener extends StatelessWidget { - /// Creates a widget that receives keyboard events. + /// Creates a widget that receives keyboard events. /// /// For text entry, consider using a [EditableText], which integrates with /// on-screen keyboards and input method editors (IMEs). diff --git a/packages/flutter/lib/src/widgets/localizations.dart b/packages/flutter/lib/src/widgets/localizations.dart index 5e22744ee358a..8d6e4230dc0a9 100644 --- a/packages/flutter/lib/src/widgets/localizations.dart +++ b/packages/flutter/lib/src/widgets/localizations.dart @@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'basic.dart'; -import 'container.dart'; import 'debug.dart'; import 'framework.dart'; @@ -598,7 +597,7 @@ class _LocalizationsState extends State { @override Widget build(BuildContext context) { if (_locale == null) { - return Container(); + return const SizedBox.shrink(); } return Semantics( textDirection: _textDirection, diff --git a/packages/flutter/lib/src/widgets/magnifier.dart b/packages/flutter/lib/src/widgets/magnifier.dart index 930657eab1235..35eb0ac02fe83 100644 --- a/packages/flutter/lib/src/widgets/magnifier.dart +++ b/packages/flutter/lib/src/widgets/magnifier.dart @@ -168,7 +168,7 @@ class MagnifierController { /// final MagnifierController myMagnifierController = MagnifierController(); /// /// // Placed below the magnifier, so it will show. - /// Overlay.of(context)!.insert(OverlayEntry( + /// Overlay.of(context).insert(OverlayEntry( /// builder: (BuildContext context) => const Text('I WILL display in the magnifier'))); /// /// // Will display in the magnifier, since this entry was passed to show. @@ -176,7 +176,7 @@ class MagnifierController { /// builder: (BuildContext context) => /// const Text('I WILL display in the magnifier')); /// - /// Overlay.of(context)! + /// Overlay.of(context) /// .insert(displayInMagnifier); /// myMagnifierController.show( /// context: context, @@ -186,10 +186,10 @@ class MagnifierController { /// )); /// /// // By default, new entries will be placed over the top entry. - /// Overlay.of(context)!.insert(OverlayEntry( + /// Overlay.of(context).insert(OverlayEntry( /// builder: (BuildContext context) => const Text('I WILL NOT display in the magnifier'))); /// - /// Overlay.of(context)!.insert( + /// Overlay.of(context).insert( /// below: /// myMagnifierController.overlayEntry, // Explicitly placed below the magnifier. /// OverlayEntry( @@ -246,7 +246,7 @@ class MagnifierController { overlayEntry!.remove(); } - final OverlayState? overlayState = Overlay.of( + final OverlayState overlayState = Overlay.of( context, rootOverlay: true, debugRequiredFor: debugRequiredFor, @@ -260,7 +260,7 @@ class MagnifierController { _overlayEntry = OverlayEntry( builder: (BuildContext context) => capturedThemes.wrap(builder(context)), ); - overlayState!.insert(overlayEntry!, below: below); + overlayState.insert(overlayEntry!, below: below); if (animationController != null) { await animationController?.forward(); @@ -389,7 +389,7 @@ class MagnifierDecoration extends ShapeDecoration { /// gesture, on an image or text. /// {@endtemplate} /// -/// A magnifier can be convienently managed by [MagnifierController], which handles +/// A magnifier can be conveniently managed by [MagnifierController], which handles /// showing and hiding the magnifier, with an optional entry / exit animation. /// /// See: @@ -402,7 +402,7 @@ class RawMagnifier extends StatelessWidget { /// the focal point is directly under the magnifier, and there is no magnification: /// This means that a default magnifier will be entirely invisible to the naked eye, /// since it is painting exactly what is under it, exactly where it was painted - /// orignally. + /// originally. /// {@endtemplate} const RawMagnifier({ super.key, @@ -414,7 +414,7 @@ class RawMagnifier extends StatelessWidget { }) : assert(magnificationScale != 0, 'Magnification scale of 0 results in undefined behavior.'); - /// An optional widget to posiiton inside the len of the [RawMagnifier]. + /// An optional widget to position inside the len of the [RawMagnifier]. /// /// This is positioned over the [RawMagnifier] - it may be useful for tinting the /// [RawMagnifier], or drawing a crosshair like UI. diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index d5b22b51c0a49..792af72fe665f 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -17,6 +17,7 @@ import 'basic.dart'; import 'binding.dart'; import 'focus_manager.dart'; import 'focus_scope.dart'; +import 'focus_traversal.dart'; import 'framework.dart'; import 'heroes.dart'; import 'overlay.dart'; @@ -217,7 +218,7 @@ abstract class Route { TickerFuture didPush() { return TickerFuture.complete()..then((void _) { if (navigator?.widget.requestFocus ?? false) { - navigator!.focusScopeNode.requestFocus(); + navigator!.focusNode.enclosingScope?.requestFocus(); } }); } @@ -233,11 +234,11 @@ abstract class Route { @mustCallSuper void didAdd() { if (navigator?.widget.requestFocus ?? false) { - // This TickerFuture serves two purposes. First, we want to make sure - // that animations triggered by other operations will finish before focusing the - // navigator. Second, navigator.focusScopeNode might acquire more focused - // children in Route.install asynchronously. This TickerFuture will wait for - // it to finish first. + // This TickerFuture serves two purposes. First, we want to make sure that + // animations triggered by other operations will finish before focusing + // the navigator. Second, navigator.focusNode might acquire more focused + // children in Route.install asynchronously. This TickerFuture will wait + // for it to finish first. // // The later case can be found when subclasses manage their own focus scopes. // For example, ModalRoute creates a focus scope in its overlay entries. The @@ -255,7 +256,7 @@ abstract class Route { // Since the reference to the navigator will be set to null after it is // disposed, we have to do a null-safe operation in case that happens // within the same frame when it is added. - navigator?.focusScopeNode.requestFocus(); + navigator?.focusNode.enclosingScope?.requestFocus(); }); } } @@ -623,12 +624,12 @@ class NavigatorObserver { NavigatorState? get navigator => _navigators[this]; /// Expando mapping instances of NavigatorObserver to their associated - /// NavigatorState (or `null`, if there is no associated NavigatorState). The + /// NavigatorState (or `null`, if there is no associated NavigatorState). The /// reason we don't simply use a private instance field of type /// `NavigatorState?` is because as part of implementing /// https://github.com/dart-lang/language/issues/2020, it will soon become a /// runtime error to invoke a private member that is mocked in another - /// library. By using an expando rather than an instance field, we ensure + /// library. By using an expando rather than an instance field, we ensure /// that a mocked NavigatorObserver can still properly keep track of its /// associated NavigatorState. static final Expando _navigators = Expando(); @@ -3207,8 +3208,15 @@ class NavigatorState extends State with TickerProviderStateMixin, Res final Queue<_NavigatorObservation> _observedRouteAdditions = Queue<_NavigatorObservation>(); final Queue<_NavigatorObservation> _observedRouteDeletions = Queue<_NavigatorObservation>(); - /// The [FocusScopeNode] for the [FocusScope] that encloses the routes. - final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope'); + /// The [FocusScopeNode] for the [FocusScope] that encloses the topmost navigator. + @Deprecated( + 'Use focusNode.enclosingScope! instead. ' + 'This feature was deprecated after v3.1.0-0.0.pre.' + ) + FocusScopeNode get focusScopeNode => focusNode.enclosingScope!; + + /// The [FocusNode] for the [Focus] that encloses the routes. + final FocusNode focusNode = FocusNode(debugLabel: 'Navigator'); bool _debugLocked = false; // used to prevent re-entrant calls to push, pop, and friends @@ -3531,7 +3539,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return true; }()); _updateHeroController(null); - focusScopeNode.dispose(); + focusNode.dispose(); for (final _RouteEntry entry in _history) { entry.dispose(); } @@ -5226,14 +5234,18 @@ class NavigatorState extends State with TickerProviderStateMixin, Res onPointerCancel: _handlePointerUpOrCancel, child: AbsorbPointer( absorbing: false, // it's mutated directly by _cancelActivePointers above - child: FocusScope( - node: focusScopeNode, - autofocus: true, - child: UnmanagedRestorationScope( - bucket: bucket, - child: Overlay( - key: _overlayKey, - initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + child: FocusTraversalGroup( + child: Focus( + focusNode: focusNode, + autofocus: true, + skipTraversal: true, + includeSemantics: false, + child: UnmanagedRestorationScope( + bucket: bucket, + child: Overlay( + key: _overlayKey, + initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + ), ), ), ), diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart index 93f302980d721..46f5277a5133f 100644 --- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart @@ -686,6 +686,12 @@ class _NestedScrollCoordinator implements ScrollActivityDelegate, ScrollHoldCont ); } + // TODO(Piinks): https://github.com/flutter/flutter/issues/100748 + @override + Simulation? updateBallisticAnimation(double initVelocity, double initPosition) { + return null; + } + ScrollActivity createOuterBallisticScrollActivity(double velocity) { // This function creates a ballistic scroll for the outer scrollable. // @@ -1361,6 +1367,12 @@ class _NestedScrollPosition extends ScrollPosition implements ScrollActivityDele )); } + // TODO(Piinks): see https://github.com/flutter/flutter/issues/100748 + @override + Simulation? updateBallisticAnimation(double initVelocity, double initPosition) { + return null; + } + ScrollActivity createBallisticScrollActivity( Simulation? simulation, { required _NestedBallisticScrollActivityMode mode, diff --git a/packages/flutter/lib/src/widgets/overflow_bar.dart b/packages/flutter/lib/src/widgets/overflow_bar.dart index 445bd07f5b0e8..f5fd4ba9e197e 100644 --- a/packages/flutter/lib/src/widgets/overflow_bar.dart +++ b/packages/flutter/lib/src/widgets/overflow_bar.dart @@ -33,7 +33,7 @@ enum OverflowBarAlignment { /// /// This widget's width will expand to contain its children and the /// specified [spacing] until it overflows. The overflow column will -/// consume all of the available width. The [overflowAlignment] +/// consume all of the available width. The [overflowAlignment] /// defines how each child will be aligned within the overflow column /// and the [overflowSpacing] defines the gap between each child. /// diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index 3d98d8c00db7a..58e52eb568333 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -273,8 +273,9 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> { /// [OverlayEntry] objects. /// /// Although you can create an [Overlay] directly, it's most common to use the -/// overlay created by the [Navigator] in a [WidgetsApp] or a [MaterialApp]. The -/// navigator uses its overlay to manage the visual appearance of its routes. +/// overlay created by the [Navigator] in a [WidgetsApp], [CupertinoApp] or a +/// [MaterialApp]. The navigator uses its overlay to manage the visual +/// appearance of its routes. /// /// The [Overlay] widget uses a custom stack implementation, which is very /// similar to the [Stack] widget. The main use case of [Overlay] is related to @@ -298,6 +299,7 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> { /// * [OverlayState], which is used to insert the entries into the overlay. /// * [WidgetsApp], which inserts an [Overlay] widget indirectly via its [Navigator]. /// * [MaterialApp], which inserts an [Overlay] widget indirectly via its [Navigator]. +/// * [CupertinoApp], which inserts an [Overlay] widget indirectly via its [Navigator]. /// * [Stack], which allows directly displaying a stack of widgets. class Overlay extends StatefulWidget { /// Creates an overlay. @@ -306,7 +308,8 @@ class Overlay extends StatefulWidget { /// [OverlayState] is initialized. /// /// Rather than creating an overlay, consider using the overlay that is - /// created by the [Navigator] in a [WidgetsApp] or a [MaterialApp] for the application. + /// created by the [Navigator] in a [WidgetsApp], [CupertinoApp], or a + /// [MaterialApp] for the application. const Overlay({ super.key, this.initialEntries = const [], @@ -334,40 +337,46 @@ class Overlay extends StatefulWidget { /// Defaults to [Clip.hardEdge], and must not be null. final Clip clipBehavior; - /// The state from the closest instance of this class that encloses the given context. + /// The [OverlayState] from the closest instance of [Overlay] that encloses + /// the given context, and, in debug mode, will throw if one is not found. /// - /// In debug mode, if the `debugRequiredFor` argument is provided then this - /// function will assert that an overlay was found and will throw an exception - /// if not. The exception attempts to explain that the calling [Widget] (the - /// one given by the `debugRequiredFor` argument) needs an [Overlay] to be - /// present to function. + /// In debug mode, if the `debugRequiredFor` argument is provided and an + /// overlay isn't found, then this function will throw an exception containing + /// the runtime type of the given widget in the error message. The exception + /// attempts to explain that the calling [Widget] (the one given by the + /// `debugRequiredFor` argument) needs an [Overlay] to be present to function. + /// If `debugRequiredFor` is not supplied, then the error message is more + /// generic. /// /// Typical usage is as follows: /// /// ```dart - /// OverlayState overlay = Overlay.of(context)!; + /// OverlayState overlay = Overlay.of(context); /// ``` /// /// If `rootOverlay` is set to true, the state from the furthest instance of - /// this class is given instead. Useful for installing overlay entries - /// above all subsequent instances of [Overlay]. + /// this class is given instead. Useful for installing overlay entries above + /// all subsequent instances of [Overlay]. /// /// This method can be expensive (it walks the element tree). - static OverlayState? of( + /// + /// See also: + /// + /// * [Overlay.maybeOf] for a similar function that returns null if an + /// [Overlay] is not found. + static OverlayState of( BuildContext context, { bool rootOverlay = false, Widget? debugRequiredFor, }) { - final OverlayState? result = rootOverlay - ? context.findRootAncestorStateOfType() - : context.findAncestorStateOfType(); + final OverlayState? result = maybeOf(context, rootOverlay: rootOverlay); assert(() { - if (debugRequiredFor != null && result == null) { + if (result == null) { final List information = [ ErrorSummary('No Overlay widget found.'), - ErrorDescription('${debugRequiredFor.runtimeType} widgets require an Overlay widget ancestor for correct operation.'), - ErrorHint('The most common way to add an Overlay to an application is to include a MaterialApp or Navigator widget in the runApp() call.'), - DiagnosticsProperty('The specific widget that failed to find an overlay was', debugRequiredFor, style: DiagnosticsTreeStyle.errorProperty), + ErrorDescription('${debugRequiredFor?.runtimeType ?? 'Some'} widgets require an Overlay widget ancestor for correct operation.'), + ErrorHint('The most common way to add an Overlay to an application is to include a MaterialApp, CupertinoApp or Navigator widget in the runApp() call.'), + if (debugRequiredFor != null) DiagnosticsProperty('The specific widget that failed to find an overlay was', debugRequiredFor, style: DiagnosticsTreeStyle.errorProperty), if (context.widget != debugRequiredFor) context.describeElement('The context from which that widget was searching for an overlay was'), ]; @@ -376,7 +385,36 @@ class Overlay extends StatefulWidget { } return true; }()); - return result; + return result!; + } + + /// The [OverlayState] from the closest instance of [Overlay] that encloses + /// the given context, if any. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// OverlayState? overlay = Overlay.maybeOf(context); + /// ``` + /// + /// If `rootOverlay` is set to true, the state from the furthest instance of + /// this class is given instead. Useful for installing overlay entries above + /// all subsequent instances of [Overlay]. + /// + /// This method can be expensive (it walks the element tree). + /// + /// See also: + /// + /// * [Overlay.of] for a similar function that returns a non-nullable result + /// and throws if an [Overlay] is not found. + + static OverlayState? maybeOf( + BuildContext context, { + bool rootOverlay = false, + }) { + return rootOverlay + ? context.findRootAncestorStateOfType() + : context.findAncestorStateOfType(); } @override diff --git a/packages/flutter/lib/src/widgets/pages.dart b/packages/flutter/lib/src/widgets/pages.dart index 4fe48202ce1c6..cc726c7e6ca91 100644 --- a/packages/flutter/lib/src/widgets/pages.dart +++ b/packages/flutter/lib/src/widgets/pages.dart @@ -19,7 +19,7 @@ abstract class PageRoute extends ModalRoute { PageRoute({ super.settings, this.fullscreenDialog = false, - this.preferRasterization = true, + this.allowSnapshotting = true, }); /// {@template flutter.widgets.PageRoute.fullscreenDialog} @@ -33,7 +33,7 @@ abstract class PageRoute extends ModalRoute { final bool fullscreenDialog; @override - final bool preferRasterization; + final bool allowSnapshotting; @override bool get opaque => true; @@ -80,7 +80,7 @@ class PageRouteBuilder extends PageRoute { this.barrierLabel, this.maintainState = true, super.fullscreenDialog, - super.preferRasterization = true, + super.allowSnapshotting = true, }) : assert(pageBuilder != null), assert(transitionsBuilder != null), assert(opaque != null), diff --git a/packages/flutter/lib/src/widgets/raster_widget.dart b/packages/flutter/lib/src/widgets/raster_widget.dart deleted file mode 100644 index 07ec0c9bac491..0000000000000 --- a/packages/flutter/lib/src/widgets/raster_widget.dart +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:ui' as ui; - -import 'package:flutter/rendering.dart'; - -import 'basic.dart'; -import 'framework.dart'; -import 'media_query.dart'; - -/// Controls how the [RasterWidget] paints its children via the [RasterWidgetController]. -enum RasterizeMode { - /// the children are rasterized, but only if all descendants can be rasterized. - /// - /// This setting is the default state of the [RasterWidgetController]. - /// - /// If there is a platform view in the children of a raster widget - /// and a [RasterWidgetFallbackDelegate]h as been provided to the raster_widget, - /// this fallback delegate will be used to render the children instead of the image. - /// If there is no fallback delegate, an excpetion will be thrown - enabled, - - /// The children are rasterized and any child platform views are ignored. - /// - /// In this state a [RasterWidgetFallbackDelegate] is never used. Generally this - /// can be useful if there is a platform view descendant that does not need to - /// be included in the raster. - forced, - - /// the children are not rasterized and the [RasterWidgetFallbackDelegate], - /// if provided, is used to draw the children. - /// - /// - fallback, -} - -/// A controller for the [RasterWidget] that controls when the child image is displayed -/// and when to regenerated the child image. -/// -/// When the value of [rasterize] is true, the [RasterWidget] will paint the child -/// widgets based on the [RasterizeMode] of the raster widget. -/// -/// To force [RasterWidget] to recreate the child image, call [clear]. -class RasterWidgetController extends ChangeNotifier { - /// Create a new [RasterWidgetController]. - /// - /// By default, [rasterize] is `false` and cannot be `null`. - RasterWidgetController({ - bool rasterize = false, - }) : _rasterize = rasterize; - - /// Reset the raster held by any listening [RasterWidget]. - /// - /// This has no effect if [rasterize] is `false`. - void clear() { - notifyListeners(); - } - - /// Whether a rasterized version of this render objects child is drawn in - /// place of the child. - bool get rasterize => _rasterize; - bool _rasterize; - set rasterize(bool value) { - if (value == rasterize) { - return; - } - _rasterize = value; - notifyListeners(); - } -} - -/// A widget that replaces its child with a rasterized version of the child. -/// -/// By default, the child is drawn as is. The default [delegate] simply scales -/// down the image by the current device pixel ratio and paints it into the -/// canvas. How this image is drawn can be customized by providing a new -/// subclass of [RasterWidgetDelegate] to the [delegate] argument. -/// -/// Caveats: -/// -/// The contents of platform views cannot be captured by a raster -/// widget. If a platform view is encountered, then the raster widget will -/// determine how to render its children based on the [RasterizeMode]. This -/// defaults to [RasterizeMode.enabled] which will throw an exception if a platform -/// view is encountered. -/// -/// This widget is not supported on the HTML backend of Flutter for the web. -class RasterWidget extends SingleChildRenderObjectWidget { - /// Create a new [RasterWidget]. - /// - /// The [controller] and [child] arguments are required. - const RasterWidget({ - super.key, - this.delegate = const _RasterDefaultDelegate(), - this.fallback, - this.mode = RasterizeMode.enabled, - required this.controller, - required super.child - }); - - /// A delegate that allows customization of how the image is painted. - /// - /// If not provided, defaults to a delegate which paints the child as is. - final RasterWidgetDelegate delegate; - - /// The controller that determines when to display the children as an image. - final RasterWidgetController controller; - - /// A fallback delegate which is used if the child layers contains a platform view. - final RasterWidgetFallbackDelegate? fallback; - - /// Configuration that controls how the raster widget decides to draw its children. - /// - /// Defaults to [RasterizeMode.enabled], which throws an error when a platform view - /// or other un-rasterizable view is encountered. - /// - /// See [RasterizeMode] for more information. - final RasterizeMode mode; - - @override - RenderObject createRenderObject(BuildContext context) { - return RenderRasterWidget( - delegate: delegate, - controller: controller, - fallback: fallback, - mode: mode, - devicePixelRatio: MediaQuery.maybeOf(context)?.devicePixelRatio ?? 1.0, - ); - } - - @override - void updateRenderObject(BuildContext context, covariant RenderRasterWidget renderObject) { - renderObject - ..delegate = delegate - ..controller = controller - ..fallback = fallback - ..mode = mode - ..devicePixelRatio = MediaQuery.maybeOf(context)?.devicePixelRatio ?? 1.0; - } -} - -/// A delegate which the [RasterWidget] can use to fallback to regular rendering -/// if a platform view is present in the layer tree. -/// -/// Consumers of [RasterWidget] should almost never use this delegate. For the most part, -/// the raster widget only functions as a performance improvement. If a platform view is -/// present, the performance improving qualities aren't possible and using this API is -/// pointless. -/// -/// Instead, this interface is useful if a generic/reusable widget is being created which -/// may include a platform view and it needs to handle this transparently. For example, the -/// framework uses this for the zoom page transition so that navigating to a page shows the same -/// animation whether or not there is a platform view. -abstract class RasterWidgetFallbackDelegate { - /// const constructor so that subclasses can be const. - const RasterWidgetFallbackDelegate(); - - /// Paint the child via [painter], applying any effects that would have been painted - /// with the [RasterWidgetDelegate]. - /// - /// The [offset] and [size] are the location and dimensions of the render object. - void paintFallback(PaintingContext context, Offset offset, Size size, PaintingContextCallback painter); -} - -/// A delegate used to draw the image representing the rasterized child. -/// -/// The delegate can call [notifyListeners] to have the raster widget -/// re-paint (re-using the same raster). This allows animations to be connected -/// to the raster and performed without re-rasterization of children. For -/// certain scale or perspective changing transforms, such as a rotation, this -/// can be significantly faster than performing the same animation at the -/// widget level. -/// -/// By default, the [RasterWidget] includes a delegate that draws the child raster -/// exactly as the child widgets would have been drawn. Nevertheless, this can -/// also be used to efficiently transform the child raster and apply complex paint -/// effects. -/// -/// {@tool snippet} -/// -/// The following method shows how to efficiently rotate the child raster. -/// -/// ```dart -/// void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { -/// const double radians = 0.5; // Could be driven by an animation. -/// final Matrix4 transform = Matrix4.rotationZ(radians); -/// context.canvas.transform(transform.storage); -/// final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); -/// final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); -/// final Paint paint = Paint() -/// ..filterQuality = FilterQuality.low; -/// context.canvas.drawImageRect(image, src, dst, paint); -/// } -/// ``` -/// {@end-tool} -abstract class RasterWidgetDelegate extends ChangeNotifier { - /// Called whenever the [image] that represents a [RasterWidget]s child should be painted. - /// - /// The image is rasterized at the physical pixel resolution and should be scaled down by - /// [pixelRatio] to account for device independent pixels. - /// - /// There is no offset given in this paint method, as the parent is an [OffsetLayer] all - /// offsets are [Offset.zero]. - /// - /// {@tool snippet} - /// - /// The follow method shows how the default implementation of the delegate used by the - /// [RasterWidget] paints the child image. This must account for the fact that the image - /// width and height will be given in physical pixels, while the image must be painted with - /// device independent pixels. That is, the width and height of the image is the widget and - /// height of the provided `size`, multiplied by the `pixelRatio`: - /// - /// ```dart - /// void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { - /// final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); - /// final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); - /// final Paint paint = Paint() - /// ..filterQuality = FilterQuality.low; - /// context.canvas.drawImageRect(image, src, dst, paint); - /// } - /// ``` - /// {@end-tool} - void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio); - - /// Called whenever a new instance of the raster widget delegate class is - /// provided to the [RenderRasterWidget] object, or any time that a new - /// [RasterWidgetDelegate] object is created with a new instance of the - /// delegate class (which amounts to the same thing, because the latter is - /// implemented in terms of the former). - /// - /// If the new instance represents different information than the old - /// instance, then the method should return true, otherwise it should return - /// false. - /// - /// If the method returns false, then the [paint] call might be optimized - /// away. - /// - /// It's possible that the [paint] method will get called even if - /// [shouldRepaint] returns false (e.g. if an ancestor or descendant needed to - /// be repainted). It's also possible that the [paint] method will get called - /// without [shouldRepaint] being called at all (e.g. if the box changes - /// size). - /// - /// Changing the delegate will not cause the child image retained by the - /// [RenderRasterWidget] to be updated. Instead, [RasterWidgetController.clear] can - /// be used to force the generation of a new image. - /// - /// The `oldDelegate` argument will never be null. - bool shouldRepaint(covariant RasterWidgetDelegate oldDelegate); -} - -/// A render object that draws its child as a [ui.Image]. -class RenderRasterWidget extends RenderProxyBox { - /// Create a new [RenderRasterWidget]. - RenderRasterWidget({ - required RasterWidgetDelegate delegate, - required double devicePixelRatio, - required RasterWidgetController controller, - required RasterizeMode mode, - RasterWidgetFallbackDelegate? fallback, - }) : _delegate = delegate, - _devicePixelRatio = devicePixelRatio, - _controller = controller, - _fallback = fallback, - _mode = mode; - - /// The device pixel ratio used to create the child image. - double get devicePixelRatio => _devicePixelRatio; - double _devicePixelRatio; - set devicePixelRatio(double value) { - if (value == devicePixelRatio) { - return; - } - _devicePixelRatio = value; - markNeedsPaint(); - } - - /// Whether a rasterized version of this render objects child is drawn in - /// place of the child. - RasterWidgetController get controller => _controller; - RasterWidgetController _controller; - set controller(RasterWidgetController value) { - if (value == controller) { - return; - } - controller.removeListener(_onRasterValueChanged); - final bool oldValue = controller.rasterize; - _controller = value; - if (attached) { - controller.addListener(_onRasterValueChanged); - if (oldValue != controller.rasterize) { - _onRasterValueChanged(); - } - } - } - - /// The delegate used to draw the image representing the child. - RasterWidgetDelegate get delegate => _delegate; - RasterWidgetDelegate _delegate; - set delegate(RasterWidgetDelegate value) { - if (value == delegate) { - return; - } - delegate.removeListener(markNeedsPaint); - final RasterWidgetDelegate oldDelegate = _delegate; - _delegate = value; - if (attached) { - delegate.addListener(markNeedsPaint); - if (delegate.shouldRepaint(oldDelegate)) { - markNeedsPaint(); - } - } - } - - /// A fallback delegate which is used if the child layers contains a platform view. - RasterWidgetFallbackDelegate? get fallback => _fallback; - RasterWidgetFallbackDelegate? _fallback; - set fallback(RasterWidgetFallbackDelegate? value) { - if (value == fallback) { - return; - } - _fallback = value; - markNeedsPaint(); - } - - /// How the raster widget will handle platform views in child layers. - RasterizeMode get mode => _mode; - RasterizeMode _mode; - set mode(RasterizeMode value) { - if (value == _mode) { - return; - } - _mode = value; - markNeedsPaint(); - } - - ui.Image? _childRaster; - - @override - void attach(covariant PipelineOwner owner) { - delegate.addListener(markNeedsPaint); - controller.addListener(_onRasterValueChanged); - super.attach(owner); - } - - @override - void detach() { - delegate.removeListener(markNeedsPaint); - controller.removeListener(_onRasterValueChanged); - _childRaster?.dispose(); - _childRaster = null; - super.detach(); - } - - @override - void dispose() { - delegate.removeListener(markNeedsPaint); - controller.removeListener(_onRasterValueChanged); - _childRaster?.dispose(); - _childRaster = null; - super.dispose(); - } - - void _onRasterValueChanged() { - _childRaster?.dispose(); - _childRaster = null; - markNeedsPaint(); - } - - bool _hitPlatformView = false; - bool get _useFallback => _hitPlatformView || mode == RasterizeMode.fallback; - - // Paint [child] with this painting context, then convert to a raster and detach all - // children from this layer. - ui.Image? _paintAndDetachToImage() { - final OffsetLayer offsetLayer = OffsetLayer(); - final PaintingContext context = PaintingContext(offsetLayer, Offset.zero & size); - super.paint(context, Offset.zero); - // This ignore is here because this method is protected by the `PaintingContext`. Adding a new - // method that performs the work of `_paintAndDetachToImage` would avoid the need for this, but - // that would conflict with our goals of minimizing painting context. - // ignore: invalid_use_of_protected_member - context.stopRecordingIfNeeded(); - if (mode != RasterizeMode.forced && !offsetLayer.supportsRasterization()) { - _hitPlatformView = true; - if (fallback == null) { - assert(() { - throw FlutterError( - 'RasterWidget used with a child that contains a PlatformView.' - ); - }()); - } - return null; - } - final ui.Image image = offsetLayer.toImageSync(Offset.zero & size, pixelRatio: devicePixelRatio); - offsetLayer.dispose(); - return image; - } - - @override - void paint(PaintingContext context, Offset offset) { - if (size.isEmpty) { - _childRaster?.dispose(); - _childRaster = null; - return; - } - if (controller.rasterize) { - if (_useFallback) { - fallback?.paintFallback(context, offset, size, super.paint); - } else { - _childRaster ??= _paintAndDetachToImage(); - if (_childRaster == null && _useFallback) { - fallback?.paintFallback(context, offset, size, super.paint); - } else { - delegate.paint(context, offset, size, _childRaster!, devicePixelRatio); - } - } - return; - } - _childRaster?.dispose(); - _childRaster = null; - super.paint(context, offset); - } -} - -// A delegate that paints the child widget as is. -class _RasterDefaultDelegate implements RasterWidgetDelegate { - const _RasterDefaultDelegate(); - - @override - void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { - final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); - final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); - final Paint paint = Paint() - ..filterQuality = FilterQuality.low; - context.canvas.drawImageRect(image, src, dst, paint); - } - - @override - bool shouldRepaint(covariant RasterWidgetDelegate oldDelegate) => false; - - @override - void addListener(ui.VoidCallback listener) { } - - @override - void dispose() { } - - @override - bool get hasListeners => false; - - @override - void notifyListeners() { } - - @override - void removeListener(ui.VoidCallback listener) { } -} diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart index 2cfcca04af8e1..4c0cee78c26e4 100644 --- a/packages/flutter/lib/src/widgets/reorderable_list.dart +++ b/packages/flutter/lib/src/widgets/reorderable_list.dart @@ -728,7 +728,7 @@ class SliverReorderableListState extends State with Ticke ); _dragInfo!.startDrag(); - final OverlayState overlay = Overlay.of(context, debugRequiredFor: widget)!; + final OverlayState overlay = Overlay.of(context, debugRequiredFor: widget); assert(_overlayEntry == null); _overlayEntry = OverlayEntry(builder: _dragInfo!.createProxy); overlay.insert(_overlayEntry!); @@ -923,7 +923,7 @@ class SliverReorderableListState extends State with Ticke } final Widget child = widget.itemBuilder(context, index); assert(child.key != null, 'All list items must have a key'); - final OverlayState overlay = Overlay.of(context, debugRequiredFor: widget)!; + final OverlayState overlay = Overlay.of(context, debugRequiredFor: widget); return _ReorderableItem( key: _ReorderableItemGlobalKey(child.key!, index, this), index: index, @@ -1310,7 +1310,7 @@ class _DragInfo extends Drag { } Offset _overlayOrigin(BuildContext context) { - final OverlayState overlay = Overlay.of(context, debugRequiredFor: context.widget)!; + final OverlayState overlay = Overlay.of(context, debugRequiredFor: context.widget); final RenderBox overlayBox = overlay.context.findRenderObject()! as RenderBox; return overlayBox.localToGlobal(Offset.zero); } diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index 92d7bd48b872a..69a0576e9ddb2 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1060,7 +1060,7 @@ class ChildBackButtonDispatcher extends BackButtonDispatcher { final BackButtonDispatcher parent; /// The parent of this child back button dispatcher decide to let this - /// child to handle the invoke the callback request in + /// child to handle the invoke the callback request in /// [BackButtonDispatcher.invokeCallback]. /// /// Return a boolean future with true if this child will handle the request; diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index 5dbeadebbbbd5..e0606556aa237 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -134,20 +134,20 @@ abstract class TransitionRoute extends OverlayRoute { /// {@endtemplate} bool get opaque; - /// {@template flutter.widgets.TransitionRoute.preferRasterization} - /// Whether the route transition will prefer to animate a rasterized - /// snapshot of the entering/exiting routes. + /// {@template flutter.widgets.TransitionRoute.allowSnapshotting} + /// Whether the route transition will prefer to animate a snapshot of the + /// entering/exiting routes. /// /// When this value is true, certain route transitions (such as the Android - /// zoom page transition) will rasterize the entering and exiting routes. - /// These textures are then animated in place of the underlying widgets to + /// zoom page transition) will snapshot the entering and exiting routes. + /// These snapshots are then animated in place of the underlying widgets to /// improve performance of the transition. /// /// Generally this means that animations that occur on the entering/exiting /// route while the route animation plays may appear frozen - unless they /// are a hero animation or something that is drawn in a separate overlay. /// {@endtemplate} - bool get preferRasterization => true; + bool get allowSnapshotting => true; // This ensures that if we got to the dismissed state while still current, // we will still be disposed when we are eventually popped. @@ -419,7 +419,7 @@ abstract class TransitionRoute extends OverlayRoute { /// /// If true, and `nextRoute.canTransitionFrom()` is true, then the /// [ModalRoute.buildTransitions] `secondaryAnimation` will run from 0.0 - 1.0 - /// when [nextRoute] is pushed on top of this one. Similarly, if + /// when [nextRoute] is pushed on top of this one. Similarly, if /// the [nextRoute] is popped off of this route, the /// `secondaryAnimation` will run from 1.0 - 0.0. /// @@ -819,7 +819,7 @@ class _ModalScopeState extends State<_ModalScope> { ]; _listenable = Listenable.merge(animations); if (widget.route.isCurrent && _shouldRequestFocus) { - widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); + widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode); } } @@ -828,7 +828,7 @@ class _ModalScopeState extends State<_ModalScope> { super.didUpdateWidget(oldWidget); assert(widget.route == oldWidget.route); if (widget.route.isCurrent && _shouldRequestFocus) { - widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); + widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode); } } @@ -863,7 +863,7 @@ class _ModalScopeState extends State<_ModalScope> { // and route.offstage. void _routeSetState(VoidCallback fn) { if (widget.route.isCurrent && !_shouldIgnoreFocusRequest && _shouldRequestFocus) { - widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); + widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode); } setState(fn); } @@ -1213,7 +1213,7 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute Theme.of(navigator.context).backgroundColor; + /// Color get barrierColor => Theme.of(navigator.context).colorScheme.background; /// ``` /// /// {@end-tool} @@ -1749,7 +1749,7 @@ abstract class PopupRoute extends ModalRoute { bool get maintainState => true; @override - bool get preferRasterization => false; + bool get allowSnapshotting => false; } /// A [Navigator] observer that notifies [RouteAware]s of changes to the diff --git a/packages/flutter/lib/src/widgets/scroll_activity.dart b/packages/flutter/lib/src/widgets/scroll_activity.dart index b8b7b1fbee23b..96f63798dea10 100644 --- a/packages/flutter/lib/src/widgets/scroll_activity.dart +++ b/packages/flutter/lib/src/widgets/scroll_activity.dart @@ -47,6 +47,16 @@ abstract class ScrollActivityDelegate { /// Terminate the current activity and start a ballistic activity with the /// given velocity. void goBallistic(double velocity); + + /// Update the ballistic animation instead of restarting it, for example as + /// the result of a layout change after a flinging gesture. + /// + /// The [initVelocity] and [initPosition] refer to the starting values of the + /// new ballistic animation. + /// + /// Can return null if the current [ScrollPhysics.createBallisticSimulation] + /// returns null, which will trigger an [IdleScrollActivity] instead. + Simulation? updateBallisticAnimation(double initVelocity, double initPosition); } /// Base class for scrolling activities like dragging and flinging. @@ -524,13 +534,17 @@ class DragScrollActivity extends ScrollActivity { class BallisticScrollActivity extends ScrollActivity { /// Creates an activity that animates a scroll view based on a [simulation]. /// - /// The [delegate], [simulation], and [vsync] arguments must not be null. + /// The [delegate], [simulation], and [vsync] arguments must not be null. The + /// [initVelocity] and [initPosition] arguments allow the ballistic activity + /// to update the simulation instead of restarting it. BallisticScrollActivity( super.delegate, Simulation simulation, TickerProvider vsync, - this.shouldIgnorePointer, - ) { + this.shouldIgnorePointer, { + double initVelocity = 0.0, + double initPosition = 0.0, + }) : _initVelocity = initVelocity, _initPosition = initPosition { _controller = AnimationController.unbounded( debugLabel: kDebugMode ? objectRuntimeType(this, 'BallisticScrollActivity') : null, vsync: vsync, @@ -542,6 +556,10 @@ class BallisticScrollActivity extends ScrollActivity { late AnimationController _controller; + final double _initVelocity; + + final double _initPosition; + @override void resetActivity() { delegate.goBallistic(velocity); @@ -549,7 +567,13 @@ class BallisticScrollActivity extends ScrollActivity { @override void applyNewDimensions() { - delegate.goBallistic(velocity); + final Simulation? newSimulation = delegate.updateBallisticAnimation( + _initVelocity, + _initPosition, + ); + if (newSimulation != null) { + _controller.updateSimulation(newSimulation); + } } void _tick() { diff --git a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart index af0cbbf24f208..9ffb74d011a18 100644 --- a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +++ b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart @@ -102,7 +102,7 @@ class ScrollAwareImageProvider extends ImageProvider { return; } // We are in the tree, we're not scrolling too fast, the cache doesn't - // have our image, and no one has otherwise completed the stream. Go. + // have our image, and no one has otherwise completed the stream. Go. imageProvider.resolveStreamForKey(configuration, stream, key, handleError); } diff --git a/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart b/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart index 66dbdfee881e6..68b838a6c234e 100644 --- a/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart +++ b/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart @@ -12,6 +12,7 @@ import 'basic.dart'; import 'framework.dart'; import 'scroll_activity.dart'; import 'scroll_context.dart'; +import 'scroll_metrics.dart'; import 'scroll_notification.dart'; import 'scroll_physics.dart'; import 'scroll_position.dart'; @@ -141,12 +142,40 @@ class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollAc assert(hasPixels); final Simulation? simulation = physics.createBallisticSimulation(this, velocity); if (simulation != null) { - beginActivity(BallisticScrollActivity(this, simulation, context.vsync, activity?.shouldIgnorePointer ?? true)); + beginActivity(BallisticScrollActivity( + this, + simulation, + context.vsync, + activity?.shouldIgnorePointer ?? true, + initVelocity: velocity, + initPosition: pixels, + )); } else { goIdle(); } } + @override + Simulation? updateBallisticAnimation(double initVelocity, double initPosition) { + assert(hasPixels); + final FixedScrollMetrics initScrollMetrics = FixedScrollMetrics( + minScrollExtent: minScrollExtent, + maxScrollExtent: maxScrollExtent, + pixels: initPosition, + viewportDimension: viewportDimension, + axisDirection: axisDirection, + ); + final Simulation? simulation = physics.createBallisticSimulation( + initScrollMetrics, + initVelocity, + ); + if (simulation == null) { + goIdle(); + return null; + } + return simulation; + } + @override ScrollDirection get userScrollDirection => _userScrollDirection; ScrollDirection _userScrollDirection = ScrollDirection.idle; diff --git a/packages/flutter/lib/src/widgets/scroll_simulation.dart b/packages/flutter/lib/src/widgets/scroll_simulation.dart index eb12592b79e78..2d54d6ffa3004 100644 --- a/packages/flutter/lib/src/widgets/scroll_simulation.dart +++ b/packages/flutter/lib/src/widgets/scroll_simulation.dart @@ -146,11 +146,13 @@ class ClampingScrollSimulation extends Simulation { required this.velocity, this.friction = 0.015, super.tolerance, - }) : assert(_flingVelocityPenetration(0.0) == _initialVelocityPenetration) { - _duration = _flingDuration(velocity); - _distance = (velocity * _duration / _initialVelocityPenetration).abs(); + }) { + _duration = _splineFlingDuration(velocity); + _distance = _splineFlingDistance(velocity); } + final double _inflexion = 0.35; + /// The position of the particle at the beginning of the simulation. final double position; @@ -163,7 +165,7 @@ class ClampingScrollSimulation extends Simulation { /// The more friction the particle experiences, the sooner it stops. final double friction; - late double _duration; + late int _duration; late double _distance; // See DECELERATION_RATE. @@ -171,59 +173,186 @@ class ClampingScrollSimulation extends Simulation { // See computeDeceleration(). static double _decelerationForFriction(double friction) { - return friction * 61774.04968; + return 9.80665 * + 39.37 * + friction * + 1.0 * // Flutter operates on logical pixels so the DPI should be 1.0. + 160.0; } - // See getSplineFlingDuration(). Returns a value in seconds. - double _flingDuration(double velocity) { - // See mPhysicalCoeff - final double scaledFriction = friction * _decelerationForFriction(0.84); - - // See getSplineDeceleration(). - final double deceleration = math.log(0.35 * velocity.abs() / scaledFriction); - - return math.exp(deceleration / (_kDecelerationRate - 1.0)); + // See getSplineDeceleration(). + double _splineDeceleration(double velocity) { + return math.log(_inflexion * + velocity.abs() / + (friction * _decelerationForFriction(0.84))); } - // Based on a cubic curve fit to the Scroller.computeScrollOffset() values - // produced for an initial velocity of 4000. The value of Scroller.getDuration() - // and Scroller.getFinalY() were 686ms and 961 pixels respectively. - // - // Algebra courtesy of Wolfram Alpha. - // - // f(x) = scrollOffset, x is time in milliseconds - // f(x) = 3.60882×10^-6 x^3 - 0.00668009 x^2 + 4.29427 x - 3.15307 - // f(x) = 3.60882×10^-6 x^3 - 0.00668009 x^2 + 4.29427 x, so f(0) is 0 - // f(686ms) = 961 pixels - // Scale to f(0 <= t <= 1.0), x = t * 686 - // f(t) = 1165.03 t^3 - 3143.62 t^2 + 2945.87 t - // Scale f(t) so that 0.0 <= f(t) <= 1.0 - // f(t) = (1165.03 t^3 - 3143.62 t^2 + 2945.87 t) / 961.0 - // = 1.2 t^3 - 3.27 t^2 + 3.065 t - static const double _initialVelocityPenetration = 3.065; - static double _flingDistancePenetration(double t) { - return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t); + // See getSplineFlingDuration(). + int _splineFlingDuration(double velocity) { + final double deceleration = _splineDeceleration(velocity); + return (1000 * math.exp(deceleration / (_kDecelerationRate - 1.0))).round(); } - // The derivative of the _flingDistancePenetration() function. - static double _flingVelocityPenetration(double t) { - return (3.6 * t * t) - (6.54 * t) + _initialVelocityPenetration; + // See getSplineFlingDistance(). + double _splineFlingDistance(double velocity) { + final double l = _splineDeceleration(velocity); + final double decelMinusOne = _kDecelerationRate - 1.0; + return friction * + _decelerationForFriction(0.84) * + math.exp(_kDecelerationRate / decelMinusOne * l); } @override double x(double time) { - final double t = clampDouble(time / _duration, 0.0, 1.0); - return position + _distance * _flingDistancePenetration(t) * velocity.sign; + if (time == 0) { + return position; + } + final _NBSample sample = _NBSample(time, _duration); + return position + (sample.distanceCoef * _distance) * velocity.sign; } @override double dx(double time) { - final double t = clampDouble(time / _duration, 0.0, 1.0); - return _distance * _flingVelocityPenetration(t) * velocity.sign / _duration; + if (time == 0) { + return velocity; + } + final _NBSample sample = _NBSample(time, _duration); + return sample.velocityCoef * _distance / _duration * velocity.sign * 1000.0; } @override bool isDone(double time) { - return time >= _duration; + return time * 1000.0 >= _duration; } } + +class _NBSample { + _NBSample(double time, int duration) { + // See computeScrollOffset(). + final double t = time * 1000.0 / duration; + final int index = (_nbSamples * t).clamp(0, _nbSamples).round(); // ignore_clamp_double_lint + _distanceCoef = 1.0; + _velocityCoef = 0.0; + if (index < _nbSamples) { + final double tInf = index / _nbSamples; + final double tSup = (index + 1) / _nbSamples; + final double dInf = _splinePosition[index]; + final double dSup = _splinePosition[index + 1]; + _velocityCoef = (dSup - dInf) / (tSup - tInf); + _distanceCoef = dInf + (t - tInf) * _velocityCoef; + } + } + + late double _velocityCoef; + double get velocityCoef => _velocityCoef; + + late double _distanceCoef; + double get distanceCoef => _distanceCoef; + + static const int _nbSamples = 100; + + // Generated from dev/tools/generate_android_spline_data.dart. + static const List _splinePosition = [ + 0.000022888183591973643, + 0.028561000304762274, + 0.05705195792956655, + 0.08538917797618413, + 0.11349556286812107, + 0.14129881694635613, + 0.16877157254923383, + 0.19581093511175632, + 0.22239649722992452, + 0.24843841866631658, + 0.2740024733220569, + 0.298967680744136, + 0.32333234658228116, + 0.34709556909569184, + 0.3702249257894571, + 0.39272483400399893, + 0.41456988647721615, + 0.43582889025419114, + 0.4564192786416, + 0.476410299013587, + 0.4957560715637827, + 0.5145493169954743, + 0.5327205670880077, + 0.5502846891191615, + 0.5673274324802855, + 0.583810881323224, + 0.5997478744397482, + 0.615194045299478, + 0.6301165005270208, + 0.6445484042257972, + 0.6585198219185201, + 0.6720397744233084, + 0.6850997688076114, + 0.6977281404741683, + 0.7099506591298411, + 0.7217749311525871, + 0.7331784038850426, + 0.7442308394229518, + 0.7549087205105974, + 0.7652471277371271, + 0.7752251637549381, + 0.7848768260203478, + 0.7942056937103814, + 0.8032299679689082, + 0.8119428702388629, + 0.8203713516576219, + 0.8285187880808974, + 0.8363794492831295, + 0.8439768562813565, + 0.851322799855549, + 0.8584111051351724, + 0.8652534074722162, + 0.8718525580962131, + 0.8782333271742155, + 0.8843892099362031, + 0.8903155590440985, + 0.8960465359221951, + 0.9015574505919048, + 0.9068736766459904, + 0.9119951682409297, + 0.9169321898723632, + 0.9216747065581234, + 0.9262420604674766, + 0.9306331858366086, + 0.9348476990715433, + 0.9389007110754832, + 0.9427903495057521, + 0.9465220679845756, + 0.9500943036519721, + 0.9535176728088761, + 0.9567898524767604, + 0.959924306623116, + 0.9629127700159108, + 0.9657622101750765, + 0.9684818726275105, + 0.9710676079044347, + 0.9735231939498, + 0.9758514437576309, + 0.9780599066560445, + 0.9801485715370128, + 0.9821149805689633, + 0.9839677526782791, + 0.9857085499421516, + 0.9873347811966005, + 0.9888547171706613, + 0.9902689443512227, + 0.9915771042095881, + 0.9927840651641069, + 0.9938913963715834, + 0.9948987305580712, + 0.9958114963810524, + 0.9966274782266875, + 0.997352148697352, + 0.9979848677523623, + 0.9985285021374979, + 0.9989844084453229, + 0.9993537595844986, + 0.999638729860106, + 0.9998403888004533, + 0.9999602810470701, + 1.0 + ]; +} diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart index 0c32e9047a853..f157e9f693366 100644 --- a/packages/flutter/lib/src/widgets/scrollbar.dart +++ b/packages/flutter/lib/src/widgets/scrollbar.dart @@ -863,7 +863,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// If the child [ScrollView] is infinitely long, the [RawScrollbar] will not be /// painted. In this case, the scrollbar cannot accurately represent the /// relative location of the visible area, or calculate the accurate delta to -/// apply when dragging on the thumb or tapping on the track. +/// apply when dragging on the thumb or tapping on the track. /// /// ### Interaction /// @@ -1134,7 +1134,7 @@ class RawScrollbar extends StatefulWidget { /// controller: controllerOne, /// itemCount: 120, /// itemBuilder: (BuildContext context, int index) { - /// return Text('item $index'); + /// return Text('item $index'); /// }, /// ), /// ), @@ -1219,7 +1219,7 @@ class RawScrollbar extends StatefulWidget { /// controller: controllerOne, /// itemCount: 120, /// itemBuilder: (BuildContext context, int index) { - /// return Text('item $index'); + /// return Text('item $index'); /// }, /// ), /// ), diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 58bfad0df0df6..0cf2f22931561 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -204,6 +204,7 @@ class SelectableRegion extends StatefulWidget { required this.selectionControls, required this.child, this.magnifierConfiguration = TextMagnifierConfiguration.disabled, + this.onSelectionChanged, }); /// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro} @@ -230,6 +231,9 @@ class SelectableRegion extends StatefulWidget { /// [TextSelectionControls] implementation with no controls. final TextSelectionControls selectionControls; + /// Called when the selected content changes. + final ValueChanged? onSelectionChanged; + @override State createState() => _SelectableRegionState(); } @@ -252,6 +256,7 @@ class _SelectableRegionState extends State with TextSelectionD || _selectionDelegate.value.endSelectionPoint != null; Orientation? _lastOrientation; + SelectedContent? _lastSelectedContent; @override void initState() { @@ -389,8 +394,16 @@ class _SelectableRegionState extends State with TextSelectionD _selectEndTo(offset: details.globalPosition, continuous: true); } + void _updateSelectedContentIfNeeded() { + if (_lastSelectedContent?.plainText != _selectable?.getSelectedContent()?.plainText) { + _lastSelectedContent = _selectable?.getSelectedContent(); + widget.onSelectionChanged?.call(_lastSelectedContent); + } + } + void _handleMouseDragEnd(DragEndDetails details) { _finalizeSelection(); + _updateSelectedContentIfNeeded(); } void _handleTouchLongPressStart(LongPressStartDetails details) { @@ -398,6 +411,7 @@ class _SelectableRegionState extends State with TextSelectionD _selectWordAt(offset: details.globalPosition); _showToolbar(); _showHandles(); + _updateSelectedContentIfNeeded(); } void _handleTouchLongPressMoveUpdate(LongPressMoveUpdateDetails details) { @@ -406,6 +420,7 @@ class _SelectableRegionState extends State with TextSelectionD void _handleTouchLongPressEnd(LongPressEndDetails details) { _finalizeSelection(); + _updateSelectedContentIfNeeded(); } void _handleRightClickDown(TapDownDetails details) { @@ -413,6 +428,7 @@ class _SelectableRegionState extends State with TextSelectionD _selectWordAt(offset: details.globalPosition); _showHandles(); _showToolbar(location: details.globalPosition); + _updateSelectedContentIfNeeded(); } // Selection update helper methods. @@ -451,6 +467,7 @@ class _SelectableRegionState extends State with TextSelectionD void _onAnyDragEnd(DragEndDetails details) { _selectionOverlay!.hideMagnifier(shouldShowToolbar: true); _stopSelectionEndEdgeUpdate(); + _updateSelectedContentIfNeeded(); } void _stopSelectionEndEdgeUpdate() { @@ -802,6 +819,7 @@ class _SelectableRegionState extends State with TextSelectionD void _clearSelection() { _finalizeSelection(); _selectable?.dispatchSelectionEvent(const ClearSelectionEvent()); + _updateSelectedContentIfNeeded(); } Future _copy() async { @@ -836,6 +854,7 @@ class _SelectableRegionState extends State with TextSelectionD _showToolbar(); _showHandles(); } + _updateSelectedContentIfNeeded(); } @override diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 2ba89866de195..ad550843dab35 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -65,7 +65,7 @@ class KeySet { assert(_keys.length == count, 'Two or more provided keys are identical. Each key must appear only once.'); } - /// Create a [KeySet] from a set of [KeyboardKey]s. + /// Create a [KeySet] from a set of [KeyboardKey]s. /// /// Do not mutate the `keys` set after passing it to this object. /// @@ -272,7 +272,7 @@ class LogicalKeySet extends KeySet with Diagnosticable super.key4, ]); - /// Create a [LogicalKeySet] from a set of [LogicalKeyboardKey]s. + /// Create a [LogicalKeySet] from a set of [LogicalKeyboardKey]s. /// /// Do not mutate the `keys` set after passing it to this object. LogicalKeySet.fromSet(super.keys) : super.fromSet(); diff --git a/packages/flutter/lib/src/widgets/snapshot_widget.dart b/packages/flutter/lib/src/widgets/snapshot_widget.dart new file mode 100644 index 0000000000000..9ce0e73bd54b8 --- /dev/null +++ b/packages/flutter/lib/src/widgets/snapshot_widget.dart @@ -0,0 +1,444 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; + +import 'package:flutter/rendering.dart'; + +import 'basic.dart'; +import 'debug.dart'; +import 'framework.dart'; +import 'media_query.dart'; + +/// Controls how the [SnapshotWidget] paints its child. +enum SnapshotMode { + /// The child is snapshotted, but only if all descendants can be snapshotted. + /// + /// If there is a platform view in the children of a snapshot widget, the + /// snapshot will not be used and the child will be rendered using + /// [SnapshotPainter.paint]. This uses an un-snapshotted child and by default + /// paints it with no additional modification. + permissive, + + /// An error is thrown if the child cannot be snapshotted. + /// + /// This setting is the default state of the [SnapshotWidget]. + normal, + + /// The child is snapshotted and any child platform views are ignored. + /// + /// This mode can be useful if there is a platform view descendant that does + /// not need to be included in the snapshot. + forced, +} + +/// A controller for the [SnapshotWidget] that controls when the child image is displayed +/// and when to regenerated the child image. +/// +/// When the value of [allowSnapshotting] is true, the [SnapshotWidget] will paint the child +/// widgets based on the [SnapshotMode] of the snapshot widget. +/// +/// The controller notifies its listeners when the value of [allowSnapshotting] changes +/// or when [clear] is called. +/// +/// To force [SnapshotWidget] to recreate the child image, call [clear]. +class SnapshotController extends ChangeNotifier { + /// Create a new [SnapshotController]. + /// + /// By default, [allowSnapshotting] is `false` and cannot be `null`. + SnapshotController({ + bool allowSnapshotting = false, + }) : _allowSnapshotting = allowSnapshotting; + + /// Reset the snapshot held by any listening [SnapshotWidget]. + /// + /// This has no effect if [allowSnapshotting] is `false`. + void clear() { + notifyListeners(); + } + + /// Whether a snapshot of this child widget is painted in its place. + bool get allowSnapshotting => _allowSnapshotting; + bool _allowSnapshotting; + set allowSnapshotting(bool value) { + if (value == allowSnapshotting) { + return; + } + _allowSnapshotting = value; + notifyListeners(); + } +} + +/// A widget that can replace its child with a snapshoted version of the child. +/// +/// A snapshot is a frozen texture-backed representation of all child pictures +/// and layers stored as a [ui.Image]. +/// +/// This widget is useful for performing short animations that would otherwise +/// be expensive or that cannot rely on raster caching. For example, scale and +/// skew animations are often expensive to perform on complex children, as are +/// blurs. For a short animation, a widget that contains these expensive effects +/// can be replaced with a snapshot of itself and manipulated instead. +/// +/// For example, the Android Q [ZoomPageTransitionsBuilder] uses a snapshot widget +/// for the forward and entering route to avoid the expensive scale animation. +/// This also has the effect of briefly pausing any animations on the page. +/// +/// Generally, this widget should not be used in places where users expect the +/// child widget to continue animating or to be responsive, such as an unbounded +/// animation. +/// +/// Caveats: +/// +/// * The contents of platform views cannot be captured by a snapshot +/// widget. If a platform view is encountered, then the snapshot widget will +/// determine how to render its children based on the [SnapshotMode]. This +/// defaults to [SnapshotMode.normal] which will throw an exception if a +/// platform view is encountered. +/// +/// * The snapshotting functionality of this widget is not supported on the HTML +/// backend of Flutter for the Web. Setting [SnapshotController.allowSnapshotting] to true +/// may cause an error to be thrown. On the CanvasKit backend of Flutter, the +/// performance of using this widget may regress performance due to the fact +/// that both the UI and engine share a single thread. +class SnapshotWidget extends SingleChildRenderObjectWidget { + /// Create a new [SnapshotWidget]. + /// + /// The [controller] and [child] arguments are required. + const SnapshotWidget({ + super.key, + this.mode = SnapshotMode.normal, + this.painter = const _DefaultSnapshotPainter(), + required this.controller, + required super.child + }); + + /// The controller that determines when to display the children as a snapshot. + final SnapshotController controller; + + /// Configuration that controls how the snapshot widget decides to paint its children. + /// + /// Defaults to [SnapshotMode.normal], which throws an error when a platform view + /// or texture view is encountered. + /// + /// See [SnapshotMode] for more information. + final SnapshotMode mode; + + /// The painter used to paint the child snapshot or child widgets. + final SnapshotPainter painter; + + @override + RenderObject createRenderObject(BuildContext context) { + debugCheckHasMediaQuery(context); + return _RenderSnapshotWidget( + controller: controller, + mode: mode, + devicePixelRatio: MediaQuery.of(context).devicePixelRatio, + painter: painter, + ); + } + + @override + void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { + debugCheckHasMediaQuery(context); + (renderObject as _RenderSnapshotWidget) + ..controller = controller + ..mode = mode + ..devicePixelRatio = MediaQuery.of(context).devicePixelRatio + ..painter = painter; + } +} + +// A render object that conditionally converts its child into a [ui.Image] +// and then paints it in place of the child. +class _RenderSnapshotWidget extends RenderProxyBox { + // Create a new [_RenderSnapshotWidget]. + _RenderSnapshotWidget({ + required double devicePixelRatio, + required SnapshotController controller, + required SnapshotMode mode, + required SnapshotPainter painter, + }) : _devicePixelRatio = devicePixelRatio, + _controller = controller, + _mode = mode, + _painter = painter; + + /// The device pixel ratio used to create the child image. + double get devicePixelRatio => _devicePixelRatio; + double _devicePixelRatio; + set devicePixelRatio(double value) { + if (value == devicePixelRatio) { + return; + } + _devicePixelRatio = value; + if (_childRaster == null) { + return; + } else { + _childRaster?.dispose(); + _childRaster = null; + markNeedsPaint(); + } + } + + /// The painter used to paint the child snapshot or child widgets. + SnapshotPainter get painter => _painter; + SnapshotPainter _painter; + set painter(SnapshotPainter value) { + if (value == painter) { + return; + } + final SnapshotPainter oldPainter = painter; + oldPainter.removeListener(markNeedsPaint); + _painter = value; + if (oldPainter.runtimeType != painter.runtimeType || + painter.shouldRepaint(oldPainter)) { + markNeedsPaint(); + } + if (attached) { + painter.addListener(markNeedsPaint); + } + } + + /// A controller that determines whether to paint the child normally or to + /// paint a snapshotted version of that child. + SnapshotController get controller => _controller; + SnapshotController _controller; + set controller(SnapshotController value) { + if (value == controller) { + return; + } + controller.removeListener(_onRasterValueChanged); + final bool oldValue = controller.allowSnapshotting; + _controller = value; + if (attached) { + controller.addListener(_onRasterValueChanged); + if (oldValue != controller.allowSnapshotting) { + _onRasterValueChanged(); + } + } + } + + /// How the snapshot widget will handle platform views in child layers. + SnapshotMode get mode => _mode; + SnapshotMode _mode; + set mode(SnapshotMode value) { + if (value == _mode) { + return; + } + _mode = value; + markNeedsPaint(); + } + + ui.Image? _childRaster; + // Set to true if the snapshot mode was not forced and a platform view + // was encountered while attempting to snapshot the child. + bool _disableSnapshotAttempt = false; + + @override + void attach(covariant PipelineOwner owner) { + controller.addListener(_onRasterValueChanged); + painter.addListener(markNeedsPaint); + super.attach(owner); + } + + @override + void detach() { + _disableSnapshotAttempt = false; + controller.removeListener(_onRasterValueChanged); + painter.removeListener(markNeedsPaint); + _childRaster?.dispose(); + _childRaster = null; + super.detach(); + } + + @override + void dispose() { + controller.removeListener(_onRasterValueChanged); + painter.removeListener(markNeedsPaint); + _childRaster?.dispose(); + _childRaster = null; + super.dispose(); + } + + void _onRasterValueChanged() { + _disableSnapshotAttempt = false; + _childRaster?.dispose(); + _childRaster = null; + markNeedsPaint(); + } + + // Paint [child] with this painting context, then convert to a raster and detach all + // children from this layer. + ui.Image? _paintAndDetachToImage() { + final OffsetLayer offsetLayer = OffsetLayer(); + final PaintingContext context = PaintingContext(offsetLayer, Offset.zero & size); + super.paint(context, Offset.zero); + // This ignore is here because this method is protected by the `PaintingContext`. Adding a new + // method that performs the work of `_paintAndDetachToImage` would avoid the need for this, but + // that would conflict with our goals of minimizing painting context. + // ignore: invalid_use_of_protected_member + context.stopRecordingIfNeeded(); + if (mode != SnapshotMode.forced && !offsetLayer.supportsRasterization()) { + if (mode == SnapshotMode.normal) { + throw FlutterError('SnapshotWidget used with a child that contains a PlatformView.'); + } + _disableSnapshotAttempt = true; + return null; + } + final ui.Image image = offsetLayer.toImageSync(Offset.zero & size, pixelRatio: devicePixelRatio); + offsetLayer.dispose(); + return image; + } + + @override + void paint(PaintingContext context, Offset offset) { + if (size.isEmpty) { + _childRaster?.dispose(); + _childRaster = null; + return; + } + if (!controller.allowSnapshotting || _disableSnapshotAttempt) { + _childRaster?.dispose(); + _childRaster = null; + painter.paint(context, offset, size, super.paint); + return; + } + _childRaster ??= _paintAndDetachToImage(); + if (_childRaster == null) { + painter.paint(context, offset, size, super.paint); + } else { + painter.paintSnapshot(context, offset, size, _childRaster!, devicePixelRatio); + } + return; + } +} + +/// A painter used to paint either a snapshot or the child widgets that +/// would be a snapshot. +/// +/// The painter can call [notifyListeners] to have the [SnapshotWidget] +/// re-paint (re-using the same raster). This allows animations to be performed +/// without re-snapshotting of children. For certain scale or perspective changing +/// transforms, such as a rotation, this can be significantly faster than performing +/// the same animation at the widget level. +/// +/// By default, the [SnapshotWidget] includes a delegate that draws the child raster +/// exactly as the child widgets would have been drawn. Nevertheless, this can +/// also be used to efficiently transform the child raster and apply complex paint +/// effects. +/// +/// {@tool snippet} +/// +/// The following method shows how to efficiently rotate the child raster. +/// +/// ```dart +/// void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { +/// const double radians = 0.5; // Could be driven by an animation. +/// final Matrix4 transform = Matrix4.rotationZ(radians); +/// context.canvas.transform(transform.storage); +/// final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); +/// final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); +/// final Paint paint = Paint() +/// ..filterQuality = FilterQuality.low; +/// context.canvas.drawImageRect(image, src, dst, paint); +/// } +/// ``` +/// {@end-tool} +abstract class SnapshotPainter extends ChangeNotifier { + /// Called whenever the [image] that represents a [SnapshotWidget]s child should be painted. + /// + /// The image is rasterized at the physical pixel resolution and should be scaled down by + /// [pixelRatio] to account for device independent pixels. + /// + /// {@tool snippet} + /// + /// The following method shows how the default implementation of the delegate used by the + /// [SnapshotPainter] paints the snapshot. This must account for the fact that the image + /// width and height will be given in physical pixels, while the image must be painted with + /// device independent pixels. That is, the width and height of the image is the widget and + /// height of the provided `size`, multiplied by the `pixelRatio`: + /// + /// ```dart + /// void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { + /// final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); + /// final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); + /// final Paint paint = Paint() + /// ..filterQuality = FilterQuality.low; + /// context.canvas.drawImageRect(image, src, dst, paint); + /// } + /// ``` + /// {@end-tool} + void paintSnapshot(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio); + + /// Paint the child via [painter], applying any effects that would have been painted + /// in [SnapshotPainter.paintSnapshot]. + /// + /// This method is called when snapshotting is disabled, or when [SnapshotMode.permissive] + /// is used and a child platform view prevents snapshotting. + /// + /// The [offset] and [size] are the location and dimensions of the render object. + void paint(PaintingContext context, Offset offset, Size size, PaintingContextCallback painter); + + /// Called whenever a new instance of the snapshot widget delegate class is + /// provided to the [SnapshotWidget] object, or any time that a new + /// [SnapshotPainter] object is created with a new instance of the + /// delegate class (which amounts to the same thing, because the latter is + /// implemented in terms of the former). + /// + /// If the new instance represents different information than the old + /// instance, then the method should return true, otherwise it should return + /// false. + /// + /// If the method returns false, then the [paint] call might be optimized + /// away. + /// + /// It's possible that the [paint] method will get called even if + /// [shouldRepaint] returns false (e.g. if an ancestor or descendant needed to + /// be repainted). It's also possible that the [paint] method will get called + /// without [shouldRepaint] being called at all (e.g. if the box changes + /// size). + /// + /// Changing the delegate will not cause the child image retained by the + /// [SnapshotWidget] to be updated. Instead, [SnapshotController.clear] can + /// be used to force the generation of a new image. + /// + /// The `oldPainter` argument will never be null. + bool shouldRepaint(covariant SnapshotPainter oldPainter); +} + +class _DefaultSnapshotPainter implements SnapshotPainter { + const _DefaultSnapshotPainter(); + + @override + void addListener(ui.VoidCallback listener) { } + + @override + void dispose() { } + + @override + bool get hasListeners => false; + + @override + void notifyListeners() { } + + @override + void paint(PaintingContext context, ui.Offset offset, ui.Size size, PaintingContextCallback painter) { + painter(context, offset); + } + + @override + void paintSnapshot(PaintingContext context, ui.Offset offset, ui.Size size, ui.Image image, double pixelRatio) { + final Rect src = Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()); + final Rect dst = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height); + final Paint paint = Paint() + ..filterQuality = FilterQuality.low; + context.canvas.drawImageRect(image, src, dst, paint); + } + + @override + void removeListener(ui.VoidCallback listener) { } + + @override + bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false; +} diff --git a/packages/flutter/lib/src/widgets/tap_region.dart b/packages/flutter/lib/src/widgets/tap_region.dart index 4c50a7088aa65..661c7144b4da3 100644 --- a/packages/flutter/lib/src/widgets/tap_region.dart +++ b/packages/flutter/lib/src/widgets/tap_region.dart @@ -406,7 +406,7 @@ class TapRegion extends SingleChildRenderObjectWidget { /// /// * [TapRegion], a widget that inserts a [RenderTapRegion] into the render /// tree. -class RenderTapRegion extends RenderProxyBox with Diagnosticable { +class RenderTapRegion extends RenderProxyBox { /// Creates a [RenderTapRegion]. RenderTapRegion({ TapRegionRegistry? registry, @@ -464,6 +464,12 @@ class RenderTapRegion extends RenderProxyBox with Diagnosticable { Object? _groupId; set groupId(Object? value) { if (_groupId != value) { + // If the group changes, we need to unregister and re-register under the + // new group. The re-registration happens automatically in layout(). + if (_isRegistered) { + _registry!.unregisterTapRegion(this); + _isRegistered = false; + } _groupId = value; markNeedsLayout(); } @@ -515,7 +521,7 @@ class RenderTapRegion extends RenderProxyBox with Diagnosticable { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('debugLabel', debugLabel, defaultValue: null)); + properties.add(DiagnosticsProperty('debugLabel', debugLabel, defaultValue: null)); properties.add(DiagnosticsProperty('groupId', groupId, defaultValue: null)); properties.add(FlagProperty('enabled', value: enabled, ifFalse: 'DISABLED', defaultValue: true)); } diff --git a/packages/flutter/lib/src/widgets/text_editing_intents.dart b/packages/flutter/lib/src/widgets/text_editing_intents.dart index a7be37d704ccd..493e6fb711430 100644 --- a/packages/flutter/lib/src/widgets/text_editing_intents.dart +++ b/packages/flutter/lib/src/widgets/text_editing_intents.dart @@ -99,7 +99,7 @@ abstract class DirectionalCaretMovementIntent extends DirectionalTextEditingInte /// /// If true, when an [Intent] to go to the beginning/end of a wordwrapped line /// is received and the selection is already at the beginning/end of the line, - /// then the selection will be moved to the next/previous line. If false, the + /// then the selection will be moved to the next/previous line. If false, the /// selection will remain at the wordwrap. final bool continuesAtWrap; } diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 96076ae4570ef..00fc689e94155 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -120,7 +120,7 @@ abstract class TextSelectionControls { List endpoints, TextSelectionDelegate delegate, // TODO(chunhtai): Change to ValueListenable? once - // mirgration is done. https://github.com/flutter/flutter/issues/99360 + // migration is done. https://github.com/flutter/flutter/issues/99360 ClipboardStatusNotifier? clipboardStatus, Offset? lastSecondaryTapDownPosition, ); @@ -793,16 +793,16 @@ class SelectionOverlay { /// a magnifierBuilder will not be provided, or the magnifierBuilder will return null /// on platforms not mobile. /// - /// This is NOT the souce of truth for if the magnifier is up or not, + /// This is NOT the source of truth for if the magnifier is up or not, /// since magnifiers may hide themselves. If this info is needed, check /// [MagnifierController.shown]. - void showMagnifier(MagnifierOverlayInfoBearer initalInfoBearer) { + void showMagnifier(MagnifierOverlayInfoBearer initialInfoBearer) { if (_toolbar != null) { hideToolbar(); } - // Start from empty, so we don't utilize any rememnant values. - _magnifierOverlayInfoBearer.value = initalInfoBearer; + // Start from empty, so we don't utilize any remnant values. + _magnifierOverlayInfoBearer.value = initialInfoBearer; // Pre-build the magnifiers so we can tell if we've built something // or not. If we don't build a magnifiers, then we should not @@ -1062,8 +1062,7 @@ class SelectionOverlay { OverlayEntry(builder: _buildEndHandle), ]; - Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)! - .insertAll(_handles!); + Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor).insertAll(_handles!); } /// {@template flutter.widgets.SelectionOverlay.hideHandles} @@ -1085,7 +1084,7 @@ class SelectionOverlay { return; } _toolbar = OverlayEntry(builder: _buildToolbar); - Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)!.insert(_toolbar!); + Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor).insert(_toolbar!); } bool _buildScheduled = false; @@ -1156,7 +1155,7 @@ class SelectionOverlay { final Widget handle; final TextSelectionControls? selectionControls = this.selectionControls; if (selectionControls == null) { - handle = Container(); + handle = const SizedBox.shrink(); } else { handle = _SelectionHandleOverlay( type: _startHandleType, @@ -1183,7 +1182,7 @@ class SelectionOverlay { final TextSelectionControls? selectionControls = this.selectionControls; if (selectionControls == null || _startHandleType == TextSelectionHandleType.collapsed) { // Hide the second handle when collapsed. - handle = Container(); + handle = const SizedBox.shrink(); } else { handle = _SelectionHandleOverlay( type: _endHandleType, @@ -1207,7 +1206,7 @@ class SelectionOverlay { Widget _buildToolbar(BuildContext context) { if (selectionControls == null) { - return Container(); + return const SizedBox.shrink(); } final RenderBox renderBox = this.context.findRenderObject()! as RenderBox; diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 0416b26d30b3c..94185fa872440 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -34,7 +34,7 @@ import 'gesture_detector.dart'; /// [WidgetInspector.selectButtonBuilder]. typedef InspectorSelectButtonBuilder = Widget Function(BuildContext context, VoidCallback onPressed); -/// Signature for a method that registers the service extension `callback` with +/// Signature for a method that registers the service extension `callback` with /// the given `name`. /// /// Used as argument to [WidgetInspectorService.initServiceExtensions]. The diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 5120fb6da4b7f..0719ad33d912b 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -91,7 +91,6 @@ export 'src/widgets/platform_selectable_region_context_menu.dart'; export 'src/widgets/platform_view.dart'; export 'src/widgets/preferred_size.dart'; export 'src/widgets/primary_scroll_controller.dart'; -export 'src/widgets/raster_widget.dart'; export 'src/widgets/raw_keyboard_listener.dart'; export 'src/widgets/reorderable_list.dart'; export 'src/widgets/restoration.dart'; @@ -127,6 +126,7 @@ export 'src/widgets/sliver_layout_builder.dart'; export 'src/widgets/sliver_persistent_header.dart'; export 'src/widgets/sliver_prototype_extent_list.dart'; export 'src/widgets/slotted_render_object_widget.dart'; +export 'src/widgets/snapshot_widget.dart'; export 'src/widgets/spacer.dart'; export 'src/widgets/spell_check.dart'; export 'src/widgets/status_transitions.dart'; diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 076d139d83508..3f562f0573ad5 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.16.0 material_color_utilities: 0.2.0 meta: 1.8.0 - vector_math: 2.1.2 + vector_math: 2.1.3 sky_engine: sdk: flutter @@ -25,7 +25,7 @@ dev_dependencies: async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -35,6 +35,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6db4 +# PUBSPEC CHECKSUM: 5eb7 diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 52472679dc4f2..8c862ba97a325 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -256,8 +256,8 @@ void main() { MaterialApp( theme: ThemeData( primaryTextTheme: const TextTheme( - headline6: titleTextStyle, - subtitle2: subtitleTextStyle, + titleLarge: titleTextStyle, + titleSmall: subtitleTextStyle, ), ), home: const Center( @@ -302,19 +302,19 @@ void main() { theme: ThemeData( // Not used because appBarTheme is prioritized. primaryTextTheme: const TextTheme( - headline6: TextStyle( + titleLarge: TextStyle( fontSize: 12, color: Colors.grey, ), - subtitle2: TextStyle( + titleSmall: TextStyle( fontSize: 10, color: Colors.grey, ), ), appBarTheme: const AppBarTheme( textTheme: TextTheme( - headline6: titleTextStyle, - subtitle2: subtitleTextStyle, + titleLarge: titleTextStyle, + titleSmall: subtitleTextStyle, ), foregroundColor: Colors.indigo, ), diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index aec7e26b0cb9a..0ea45bddfd907 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -693,10 +693,12 @@ void main() { expect(iconColor(), color); }); - testWidgets('leading button extends to edge and is square', (WidgetTester tester) async { + testWidgets('leading widget extends to edge and is square', (WidgetTester tester) async { + final ThemeData themeData = ThemeData(platform: TargetPlatform.android); + final bool material3 = themeData.useMaterial3; await tester.pumpWidget( MaterialApp( - theme: ThemeData(platform: TargetPlatform.android), + theme: themeData, home: Scaffold( appBar: AppBar( title: const Text('X'), @@ -706,15 +708,52 @@ void main() { ), ); - final Finder hamburger = find.byTooltip('Open navigation menu'); - expect(tester.getTopLeft(hamburger), const Offset(4.0, 4.0)); - expect(tester.getSize(hamburger), const Size(48.0, 48.0)); + // Default IconButton has a size of (48x48) in M3, (56x56) in M2 + final Finder hamburger = find.byType(IconButton); + expect(tester.getTopLeft(hamburger), material3 ? const Offset(4.0, 4.0) : Offset.zero); + expect(tester.getSize(hamburger), material3 ? const Size(48.0, 48.0) : const Size(56.0, 56.0)); + + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: Container(), + title: const Text('X'), + ), + ), + ), + ); + + // Default leading widget has a size of (56x56) for both M2 and M3 + final Finder leadingBox = find.byType(Container); + expect(tester.getTopLeft(leadingBox), Offset.zero); + expect(tester.getSize(leadingBox), const Size(56.0, 56.0)); + + // The custom leading widget should still be 56x56 even if its size is smaller. + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: const SizedBox(height: 36, width: 36,), + title: const Text('X'), + ), // Doesn't really matter. Triggers a hamburger regardless. + ), + ), + ); + + final Finder leading = find.byType(SizedBox); + expect(tester.getTopLeft(leading), Offset.zero); + expect(tester.getSize(leading), const Size(56.0, 56.0)); }); testWidgets('test action is 4dp from edge and 48dp min', (WidgetTester tester) async { + final ThemeData theme = ThemeData(platform: TargetPlatform.android); + final bool material3 = theme.useMaterial3; await tester.pumpWidget( MaterialApp( - theme: ThemeData(platform: TargetPlatform.android), + theme: theme, home: Scaffold( appBar: AppBar( title: const Text('X'), @@ -744,7 +783,7 @@ void main() { final Finder shareButton = find.widgetWithIcon(IconButton, Icons.share); // The 20dp icon is expanded to fill the IconButton's touch target to 48dp. - expect(tester.getSize(shareButton), const Size(48.0, 56.0)); + expect(tester.getSize(shareButton), material3 ? const Size(48.0, 48.0) : const Size(48.0, 56.0)); }); testWidgets('SliverAppBar default configuration', (WidgetTester tester) async { @@ -2876,6 +2915,42 @@ void main() { expect(actionIconColor(), foregroundColor); }); + testWidgets('Leading, title, and actions show correct default colors', (WidgetTester tester) async { + final ThemeData themeData = ThemeData.from( + colorScheme: const ColorScheme.light( + onPrimary: Colors.blue, + onSurface: Colors.red, + onSurfaceVariant: Colors.yellow), + ); + final bool material3 = themeData.useMaterial3; + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: const Icon(Icons.add_circle), + title: const Text('title'), + actions: const [ + Icon(Icons.ac_unit) + ], + ), + ), + ), + ); + + Color textColor() { + return tester.renderObject(find.text('title')).text.style!.color!; + } + Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; + + // M2 default color are onPrimary, and M3 has onSurface for leading and title, + // onSurfaceVariant for actions. + expect(textColor(), material3 ? Colors.red : Colors.blue); + expect(leadingIconColor(), material3 ? Colors.red : Colors.blue); + expect(actionIconColor(), material3 ? Colors.yellow : Colors.blue); + }); + // Regression test for https://github.com/flutter/flutter/issues/107305 group('Icons are colored correctly by IconTheme and ActionIconTheme in M3', () { testWidgets('Icons and IconButtons are colored by IconTheme in M3', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index 4892cd708d08d..6c4ba608f8a4e 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -45,7 +45,7 @@ void main() { expect(iconTheme.data, IconThemeData(color: theme.colorScheme.onSurface, size: 24)); expect(actionsIconTheme.data, IconThemeData(color: theme.colorScheme.onSurfaceVariant, size: 24)); expect(actionIconText.text.style!.color, Colors.black); - expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: theme.colorScheme.onSurface)); + expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: theme.colorScheme.onSurface)); expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); expect(tester.getSize(find.byType(AppBar)).width, 800); } else { @@ -58,7 +58,7 @@ void main() { expect(iconTheme.data, const IconThemeData(color: Colors.white)); expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); expect(actionIconText.text.style!.color, Colors.white); - expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2)); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().white.bodyMedium)); expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); expect(tester.getSize(find.byType(AppBar)).width, 800); } @@ -284,7 +284,7 @@ void main() { // - surface tint color: ColorScheme.surfaceTint // - background color: ColorScheme.surface // - foreground color: ColorScheme.onSurface - // - actions text: style bodyText2, foreground color + // - actions text: style bodyMedium, foreground color // - status bar brightness: light (based on color scheme brightness) { await tester.pumpWidget(buildFrame(lightTheme)); @@ -303,7 +303,7 @@ void main() { expect(iconTheme.data.color, lightTheme.colorScheme.onSurface); expect(actionsIconTheme.data.color, lightTheme.colorScheme.onSurface); expect(actionIconText.text.style!.color, lightTheme.colorScheme.onSurface); - expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: lightTheme.colorScheme.onSurface)); + expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onSurface)); } // M3 AppBar defaults for dark themes: @@ -312,7 +312,7 @@ void main() { // - surface tint color: ColorScheme.surfaceTint // - background color: ColorScheme.surface // - foreground color: ColorScheme.onSurface - // - actions text: style bodyText2, foreground color + // - actions text: style bodyMedium, foreground color // - status bar brightness: dark (based on background color) { await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.dark()))); @@ -332,7 +332,7 @@ void main() { expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); - expect(text.style, Typography.material2021().englishLike.bodyText2!.merge(Typography.material2021().black.bodyText2).copyWith(color: darkTheme.colorScheme.onSurface)); + expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface)); } } else { // AppBar defaults for light themes: @@ -341,7 +341,7 @@ void main() { // - surface tint color: null // - background color: ColorScheme.primary // - foreground color: ColorScheme.onPrimary - // - actions text: style bodyText2, foreground color + // - actions text: style bodyMedium, foreground color // - status bar brightness: light (based on color scheme brightness) { await tester.pumpWidget(buildFrame(lightTheme)); @@ -360,7 +360,7 @@ void main() { expect(iconTheme.data.color, lightTheme.colorScheme.onPrimary); expect(actionsIconTheme.data.color, lightTheme.colorScheme.onPrimary); expect(actionIconText.text.style!.color, lightTheme.colorScheme.onPrimary); - expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2).copyWith(color: lightTheme.colorScheme.onPrimary)); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onPrimary)); } // AppBar defaults for dark themes: @@ -369,7 +369,7 @@ void main() { // - surface tint color: null // - background color: ColorScheme.surface // - foreground color: ColorScheme.onSurface - // - actions text: style bodyText2, foreground color + // - actions text: style bodyMedium, foreground color // - status bar brightness: dark (based on background color) { await tester.pumpWidget(buildFrame(darkTheme)); @@ -389,7 +389,7 @@ void main() { expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); - expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2).copyWith(color: darkTheme.colorScheme.onSurface)); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface)); } } }); diff --git a/packages/flutter/test/material/app_builder_test.dart b/packages/flutter/test/material/app_builder_test.dart index 313aa5d2ec6db..c63b84e16b200 100644 --- a/packages/flutter/test/material/app_builder_test.dart +++ b/packages/flutter/test/material/app_builder_test.dart @@ -17,7 +17,7 @@ void main() { log.add('build'); expect(Theme.of(context).primaryColor, Colors.green); expect(Directionality.of(context), TextDirection.ltr); - expect(child, isA()); + expect(child, isA()); return const Placeholder(); }, ); diff --git a/packages/flutter/test/material/back_button_test.dart b/packages/flutter/test/material/back_button_test.dart index d4ff9a92ffab1..09d9fd1d668ca 100644 --- a/packages/flutter/test/material/back_button_test.dart +++ b/packages/flutter/test/material/back_button_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -152,9 +153,21 @@ void main() { tester.state(find.byType(Navigator)).pushNamed('/next'); await tester.pumpAndSettle(); - + final String? expectedLabel; + switch(defaultTargetPlatform) { + case TargetPlatform.android: + expectedLabel = 'Back'; + break; + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + case TargetPlatform.linux: + case TargetPlatform.macOS: + case TargetPlatform.windows: + expectedLabel = null; + } expect(tester.getSemantics(find.byType(BackButton)), matchesSemantics( tooltip: 'Back', + label: expectedLabel, isButton: true, hasEnabledState: true, isEnabled: true, @@ -162,7 +175,51 @@ void main() { isFocusable: true, )); handle.dispose(); - }); + }, variant: TargetPlatformVariant.all()); + + testWidgets('CloseButton semantics', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + MaterialApp( + home: const Material(child: Text('Home')), + routes: { + '/next': (BuildContext context) { + return const Material( + child: Center( + child: CloseButton(), + ), + ); + }, + }, + ), + ); + + tester.state(find.byType(Navigator)).pushNamed('/next'); + + await tester.pumpAndSettle(); + final String? expectedLabel; + switch(defaultTargetPlatform) { + case TargetPlatform.android: + expectedLabel = 'Close'; + break; + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + case TargetPlatform.linux: + case TargetPlatform.macOS: + case TargetPlatform.windows: + expectedLabel = null; + } + expect(tester.getSemantics(find.byType(CloseButton)), matchesSemantics( + tooltip: 'Close', + label: expectedLabel, + isButton: true, + hasEnabledState: true, + isEnabled: true, + hasTapAction: true, + isFocusable: true, + )); + handle.dispose(); + }, variant: TargetPlatformVariant.all()); testWidgets('CloseButton color', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/material/banner_theme_test.dart b/packages/flutter/test/material/banner_theme_test.dart index 7d4c73f97a2a4..db351f9ad9699 100644 --- a/packages/flutter/test/material/banner_theme_test.dart +++ b/packages/flutter/test/material/banner_theme_test.dart @@ -15,7 +15,13 @@ void main() { test('MaterialBannerThemeData null fields by default', () { const MaterialBannerThemeData bannerTheme = MaterialBannerThemeData(); expect(bannerTheme.backgroundColor, null); + expect(bannerTheme.surfaceTintColor, null); + expect(bannerTheme.shadowColor, null); + expect(bannerTheme.dividerColor, null); expect(bannerTheme.contentTextStyle, null); + expect(bannerTheme.elevation, null); + expect(bannerTheme.padding, null); + expect(bannerTheme.leadingPadding, null); }); testWidgets('Default MaterialBannerThemeData debugFillProperties', (WidgetTester tester) async { @@ -23,9 +29,9 @@ void main() { const MaterialBannerThemeData().debugFillProperties(builder); final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); expect(description, []); }); @@ -33,27 +39,43 @@ void main() { testWidgets('MaterialBannerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const MaterialBannerThemeData( - backgroundColor: Color(0xFFFFFFFF), - contentTextStyle: TextStyle(color: Color(0xFFFFFFFF)), + backgroundColor: Color(0xfffffff0), + surfaceTintColor: Color(0xfffffff1), + shadowColor: Color(0xfffffff2), + dividerColor: Color(0xfffffff3), + contentTextStyle: TextStyle(color: Color(0xfffffff4)), + elevation: 4.0, + padding: EdgeInsets.all(20.0), + leadingPadding: EdgeInsets.only(left: 8.0), ).debugFillProperties(builder); final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); expect(description, [ - 'backgroundColor: Color(0xffffffff)', - 'contentTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))', + 'backgroundColor: Color(0xfffffff0)', + 'surfaceTintColor: Color(0xfffffff1)', + 'shadowColor: Color(0xfffffff2)', + 'dividerColor: Color(0xfffffff3)', + 'contentTextStyle: TextStyle(inherit: true, color: Color(0xfffffff4))', + 'elevation: 4.0', + 'padding: EdgeInsets.all(20.0)', + 'leadingPadding: EdgeInsets(8.0, 0.0, 0.0, 0.0)', ]); }); testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); const String contentText = 'Content'; + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), home: Scaffold( body: MaterialBanner( content: const Text(contentText), + leading: const Icon(Icons.umbrella), actions: [ TextButton( child: const Text('Action'), @@ -65,16 +87,39 @@ void main() { )); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, const Color(0xffffffff)); - // Default value for ThemeData.typography is Typography.material2014() - expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2)); + expect(material.surfaceTintColor, theme.colorScheme.surfaceTint); + expect(material.shadowColor, null); + expect(material.elevation, 0.0); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); + // Default value for ThemeData.typography is Typography.material2021() + expect( + content.text.style, + Typography.material2021().englishLike.bodyMedium!.merge( + Typography.material2021().black.bodyMedium, + ), + ); + + final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); + final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); + final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); + expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. + expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. + expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. + expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. + + final Divider divider = tester.widget(find.byType(Divider)); + expect(divider.color, theme.colorScheme.surfaceVariant); }); testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), home: Scaffold( body: Builder( builder: (BuildContext context) { @@ -83,6 +128,7 @@ void main() { onTap: () { ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( content: const Text(contentText), + leading: const Icon(Icons.umbrella), actions: [ TextButton( child: const Text('Action'), @@ -105,10 +151,30 @@ void main() { await tester.pumpAndSettle(); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, const Color(0xffffffff)); - // Default value for ThemeData.typography is Typography.material2014() - expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2)); + expect(material.surfaceTintColor, theme.colorScheme.surfaceTint); + expect(material.shadowColor, null); + expect(material.elevation, 0.0); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); + // Default value for ThemeData.typography is Typography.material2021() + expect( + content.text.style, + Typography.material2021().englishLike.bodyMedium!.merge( + Typography.material2021().black.bodyMedium, + ), + ); + + final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); + final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); + final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); + expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. + expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. + expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. + expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. + + final Divider divider = tester.widget(find.byType(Divider)); + expect(divider.color, theme.colorScheme.surfaceVariant); }); testWidgets('MaterialBanner uses values from MaterialBannerThemeData', (WidgetTester tester) async { @@ -131,8 +197,12 @@ void main() { )); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, bannerTheme.backgroundColor); + expect(material.surfaceTintColor, bannerTheme.surfaceTintColor); + expect(material.shadowColor, bannerTheme.shadowColor); + expect(material.elevation, bannerTheme.elevation); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(content.text.style, bannerTheme.contentTextStyle); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); @@ -142,6 +212,8 @@ void main() { expect(contentTopLeft.dx - materialTopLeft.dx, 41); expect(leadingTopLeft.dy - materialTopLeft.dy, 19); expect(leadingTopLeft.dx - materialTopLeft.dx, 11); + + expect(find.byType(Divider), findsNothing); }); testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async { @@ -181,8 +253,12 @@ void main() { await tester.pumpAndSettle(); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, bannerTheme.backgroundColor); + expect(material.surfaceTintColor, bannerTheme.surfaceTintColor); + expect(material.shadowColor, bannerTheme.shadowColor); + expect(material.elevation, bannerTheme.elevation); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(content.text.style, bannerTheme.contentTextStyle); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); @@ -192,18 +268,26 @@ void main() { expect(contentTopLeft.dx - materialTopLeft.dx, 41); expect(leadingTopLeft.dy - materialTopLeft.dy, 19); expect(leadingTopLeft.dx - materialTopLeft.dx, 11); + + expect(find.byType(Divider), findsNothing); }); testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; + const Color surfaceTintColor = Colors.red; + const Color shadowColor = Colors.orange; const TextStyle textStyle = TextStyle(color: Colors.green); final MaterialBannerThemeData bannerTheme = _bannerTheme(); const String contentText = 'Content'; + await tester.pumpWidget(MaterialApp( theme: ThemeData(bannerTheme: bannerTheme), home: Scaffold( body: MaterialBanner( backgroundColor: backgroundColor, + surfaceTintColor: surfaceTintColor, + shadowColor: shadowColor, + elevation: 6.0, leading: const Icon(Icons.ac_unit), contentTextStyle: textStyle, content: const Text(contentText), @@ -220,8 +304,12 @@ void main() { )); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, backgroundColor); + expect(material.surfaceTintColor, surfaceTintColor); + expect(material.shadowColor, shadowColor); + expect(material.elevation, 6.0); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(content.text.style, textStyle); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); @@ -231,14 +319,18 @@ void main() { expect(contentTopLeft.dx - materialTopLeft.dx, 58); expect(leadingTopLeft.dy - materialTopLeft.dy, 24); expect(leadingTopLeft.dx - materialTopLeft.dx, 22); + + expect(find.byType(Divider), findsNothing); }); testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; + const double elevation = 6.0; const TextStyle textStyle = TextStyle(color: Colors.green); final MaterialBannerThemeData bannerTheme = _bannerTheme(); const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); + await tester.pumpWidget(MaterialApp( theme: ThemeData(bannerTheme: bannerTheme), home: Scaffold( @@ -249,6 +341,7 @@ void main() { onTap: () { ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( backgroundColor: backgroundColor, + elevation: elevation, leading: const Icon(Icons.ac_unit), contentTextStyle: textStyle, content: const Text(contentText), @@ -276,8 +369,10 @@ void main() { await tester.pumpAndSettle(); final Material material = _getMaterialFromText(tester, contentText); - final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(material.color, backgroundColor); + expect(material.elevation, elevation); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); expect(content.text.style, textStyle); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); @@ -287,6 +382,8 @@ void main() { expect(contentTopLeft.dx - materialTopLeft.dx, 58); expect(leadingTopLeft.dy - materialTopLeft.dy, 24); expect(leadingTopLeft.dx - materialTopLeft.dx, 22); + + expect(find.byType(Divider), findsNothing); }); testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async { @@ -349,12 +446,130 @@ void main() { final Material material = _getMaterialFromText(tester, contentText); expect(material.color, colorScheme.surface); }); + + group('Material 2', () { + // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 + // is turned on by default, these tests can be removed. + + testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); + const String contentText = 'Content'; + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: MaterialBanner( + content: const Text(contentText), + leading: const Icon(Icons.umbrella), + actions: [ + TextButton( + child: const Text('Action'), + onPressed: () { }, + ), + ], + ), + ), + )); + + final Material material = _getMaterialFromText(tester, contentText); + expect(material.color, const Color(0xffffffff)); + expect(material.surfaceTintColor, null); + expect(material.shadowColor, null); + expect(material.elevation, 0.0); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); + // Default value for ThemeData.typography is Typography.material2014() + expect( + content.text.style, + Typography.material2014().englishLike.bodyText2!.merge( + Typography.material2014().black.bodyText2, + ), + ); + + final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); + final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); + final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); + expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. + expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. + expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. + expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. + + final Divider divider = tester.widget(find.byType(Divider)); + expect(divider.color, theme.colorScheme.surfaceVariant); + }); + + testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); + const String contentText = 'Content'; + const Key tapTarget = Key('tap-target'); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + key: tapTarget, + onTap: () { + ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner( + content: const Text(contentText), + leading: const Icon(Icons.umbrella), + actions: [ + TextButton( + child: const Text('Action'), + onPressed: () { }, + ), + ], + )); + }, + behavior: HitTestBehavior.opaque, + child: const SizedBox( + height: 100.0, + width: 100.0, + ), + ); + }, + ), + ), + )); + await tester.tap(find.byKey(tapTarget)); + await tester.pumpAndSettle(); + + final Material material = _getMaterialFromText(tester, contentText); + expect(material.color, const Color(0xffffffff)); + expect(material.surfaceTintColor, null); + expect(material.shadowColor, null); + expect(material.elevation, 0.0); + + final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); + // Default value for ThemeData.typography is Typography.material2014() + expect( + content.text.style, + Typography.material2014().englishLike.bodyText2!.merge( + Typography.material2014().black.bodyText2, + ), + ); + + final Offset rowTopLeft = tester.getTopLeft(find.byType(Row)); + final Offset materialTopLeft = tester.getTopLeft(_materialFinder()); + final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella)); + expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding. + expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding. + expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding. + expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding. + + final Divider divider = tester.widget(find.byType(Divider)); + expect(divider.color, theme.colorScheme.surfaceVariant); + }); + }); } MaterialBannerThemeData _bannerTheme() { return const MaterialBannerThemeData( backgroundColor: Colors.orange, + surfaceTintColor: Colors.yellow, + shadowColor: Colors.red, + dividerColor: Colors.green, contentTextStyle: TextStyle(color: Colors.pink), + elevation: 4.0, padding: EdgeInsets.all(5), leadingPadding: EdgeInsets.all(6), ); diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 51b1cd9fb00a0..d01aad537e5fd 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -51,7 +51,7 @@ void main() { expect(description, [ 'backgroundColor: Color(0xffffffff)', 'elevation: 2.0', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'clipBehavior: Clip.antiAlias', 'constraints: BoxConstraints(200.0<=w<=640.0, 0.0<=h<=Infinity)', ]); diff --git a/packages/flutter/test/material/button_style_test.dart b/packages/flutter/test/material/button_style_test.dart index 11de84c7b5d12..44599e55f5e7b 100644 --- a/packages/flutter/test/material/button_style_test.dart +++ b/packages/flutter/test/material/button_style_test.dart @@ -88,8 +88,8 @@ void main() { 'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))', 'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))', 'iconSize: MaterialStatePropertyAll(48.1)', - 'side: MaterialStatePropertyAll(BorderSide(Color(0xfffffff6), 4.0, BorderStyle.solid))', - 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none)))', + 'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))', + 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))', 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))', 'tapTargetSize: shrinkWrap', 'animationDuration: 0:00:01.000000', diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index 06c163ab72d77..4b49948c4c216 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -8,12 +8,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { + final ThemeData theme = ThemeData(); setUp(() { debugResetSemanticsIdCounter(); }); @@ -21,7 +23,7 @@ void main() { testWidgets('Checkbox size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { await tester.pumpWidget( Theme( - data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded), + data: theme.copyWith(materialTapTargetSize: MaterialTapTargetSize.padded), child: Directionality( textDirection: TextDirection.ltr, child: Material( @@ -40,7 +42,7 @@ void main() { await tester.pumpWidget( Theme( - data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), + data: theme.copyWith(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), child: Directionality( textDirection: TextDirection.ltr, child: Material( @@ -61,10 +63,13 @@ void main() { testWidgets('CheckBox semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(Material( - child: Checkbox( - value: false, - onChanged: (bool? b) { }, + await tester.pumpWidget(Theme( + data: theme, + child: Material( + child: Checkbox( + value: false, + onChanged: (bool? b) { }, + ), ), )); @@ -76,10 +81,13 @@ void main() { isFocusable: true, )); - await tester.pumpWidget(Material( - child: Checkbox( - value: true, - onChanged: (bool? b) { }, + await tester.pumpWidget(Theme( + data: theme, + child: Material( + child: Checkbox( + value: true, + onChanged: (bool? b) { }, + ), ), )); @@ -92,10 +100,13 @@ void main() { isFocusable: true, )); - await tester.pumpWidget(const Material( - child: Checkbox( - value: false, - onChanged: null, + await tester.pumpWidget(Theme( + data: theme, + child: const Material( + child: Checkbox( + value: false, + onChanged: null, + ), ), )); @@ -113,10 +124,13 @@ void main() { hasEnabledState: true, )); - await tester.pumpWidget(const Material( - child: Checkbox( - value: true, - onChanged: null, + await tester.pumpWidget(Theme( + data: theme, + child: const Material( + child: Checkbox( + value: true, + onChanged: null, + ), ), )); @@ -131,13 +145,16 @@ void main() { testWidgets('Can wrap CheckBox with Semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); - await tester.pumpWidget(Material( - child: Semantics( - label: 'foo', - textDirection: TextDirection.ltr, - child: Checkbox( - value: false, - onChanged: (bool? b) { }, + await tester.pumpWidget(Theme( + data: theme, + child: Material( + child: Semantics( + label: 'foo', + textDirection: TextDirection.ltr, + child: Checkbox( + value: false, + onChanged: (bool? b) { }, + ), ), ), )); @@ -158,19 +175,22 @@ void main() { bool? checkBoxValue; await tester.pumpWidget( - Material( - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Checkbox( - tristate: true, - value: checkBoxValue, - onChanged: (bool? value) { - setState(() { - checkBoxValue = value; - }); - }, - ); - }, + Theme( + data: theme, + child: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Checkbox( + tristate: true, + value: checkBoxValue, + onChanged: (bool? value) { + setState(() { + checkBoxValue = value; + }); + }, + ); + }, + ), ), ), ); @@ -201,11 +221,14 @@ void main() { testWidgets('has semantics for tristate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( - Material( - child: Checkbox( - tristate: true, - value: null, - onChanged: (bool? newValue) { }, + Theme( + data: theme, + child: Material( + child: Checkbox( + tristate: true, + value: null, + onChanged: (bool? newValue) { }, + ), ), ), ); @@ -221,11 +244,14 @@ void main() { ), hasLength(1)); await tester.pumpWidget( - Material( - child: Checkbox( - tristate: true, - value: true, - onChanged: (bool? newValue) { }, + Theme( + data: theme, + child: Material( + child: Checkbox( + tristate: true, + value: true, + onChanged: (bool? newValue) { }, + ), ), ), ); @@ -242,11 +268,14 @@ void main() { ), hasLength(1)); await tester.pumpWidget( - Material( - child: Checkbox( - tristate: true, - value: false, - onChanged: (bool? newValue) { }, + Theme( + data: theme, + child: Material( + child: Checkbox( + tristate: true, + value: false, + onChanged: (bool? newValue) { }, + ), ), ), ); @@ -273,18 +302,21 @@ void main() { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget( - Material( - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Checkbox( - value: checkboxValue, - onChanged: (bool? value) { - setState(() { - checkboxValue = value; - }); - }, - ); - }, + Theme( + data: theme, + child: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Checkbox( + value: checkboxValue, + onChanged: (bool? value) { + setState(() { + checkboxValue = value; + }); + }, + ); + }, + ), ), ), ); @@ -306,15 +338,18 @@ void main() { testWidgets('CheckBox tristate rendering, programmatic transitions', (WidgetTester tester) async { Widget buildFrame(bool? checkboxValue) { - return Material( - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Checkbox( - tristate: true, - value: checkboxValue, - onChanged: (bool? value) { }, - ); - }, + return Theme( + data: theme, + child: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Checkbox( + tristate: true, + value: checkboxValue, + onChanged: (bool? value) { }, + ); + }, + ), ), ); } @@ -391,10 +426,14 @@ void main() { activeColor = const Color(0xFF00FF00); + ThemeData themeData = ThemeData(); + final bool material3 = themeData.useMaterial3; + final ColorScheme colorScheme = material3 + ? const ColorScheme.light().copyWith(primary: activeColor) + : const ColorScheme.light().copyWith(secondary: activeColor); + themeData = themeData.copyWith(colorScheme: colorScheme); await tester.pumpWidget(buildFrame( - themeData: ThemeData( - colorScheme: const ColorScheme.light() - .copyWith(secondary: activeColor))), + themeData: themeData), ); await tester.pumpAndSettle(); expect(getCheckboxRenderer(), paints..path(color: activeColor)); // paints's color is 0xFF00FF00 (theme) @@ -412,6 +451,7 @@ void main() { bool? value = true; Widget buildApp({bool enabled = true}) { return MaterialApp( + theme: theme, home: Material( child: Center( child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { @@ -434,13 +474,19 @@ void main() { await tester.pumpWidget(buildApp()); await tester.pumpAndSettle(); + final bool material3 = theme.useMaterial3; expect(focusNode.hasPrimaryFocus, isTrue); expect( Material.of(tester.element(find.byType(Checkbox))), - paints - ..circle(color: Colors.orange[500]) - ..path(color: const Color(0xff2196f3)) - ..path(color: Colors.white), + material3 + ? (paints + ..circle(color: Colors.orange[500]) + ..path(color: const Color(0xff2196f3)) + ..path(color: theme.colorScheme.onPrimary)) + : (paints + ..circle(color: Colors.orange[500]) + ..path(color: const Color(0xff2196f3)) + ..path(color: Colors.white)) ); // Check the false value. @@ -453,7 +499,7 @@ void main() { paints ..circle(color: Colors.orange[500]) ..drrect( - color: const Color(0x8a000000), + color: material3 ? theme.colorScheme.onSurface : const Color(0x8a000000), outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)), inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)), ), @@ -468,7 +514,7 @@ void main() { Material.of(tester.element(find.byType(Checkbox))), paints ..drrect( - color: const Color(0x61000000), + color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000), outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)), inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)), ), @@ -480,6 +526,7 @@ void main() { const double splashRadius = 30; Widget buildApp() { return MaterialApp( + theme: theme, home: Material( child: Center( child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { @@ -506,8 +553,10 @@ void main() { testWidgets('Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; + final bool material3 = theme.useMaterial3; Widget buildApp({bool enabled = true}) { return MaterialApp( + theme: theme, home: Material( child: Center( child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { @@ -531,7 +580,7 @@ void main() { Material.of(tester.element(find.byType(Checkbox))), paints ..path(color: const Color(0xff2196f3)) - ..path(color: const Color(0xffffffff),style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), ); // Start hovering @@ -544,7 +593,7 @@ void main() { Material.of(tester.element(find.byType(Checkbox))), paints ..path(color: const Color(0xff2196f3)) - ..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), ); // Check what happens when disabled. @@ -553,8 +602,8 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), paints - ..path(color: const Color(0x61000000)) - ..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000)) + ..path(color: material3 ? theme.colorScheme.surface : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), ); }); @@ -563,6 +612,7 @@ void main() { bool? value = true; Widget buildApp({bool enabled = true}) { return MaterialApp( + theme: theme, home: Material( child: Center( child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { @@ -603,6 +653,7 @@ void main() { Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( MaterialApp( + theme: theme, home: Material( child: Center( child: Checkbox( @@ -693,6 +744,7 @@ void main() { // Test Checkbox() constructor await tester.pumpWidget( MaterialApp( + theme: theme, home: Scaffold( body: Align( alignment: Alignment.topLeft, @@ -721,6 +773,7 @@ void main() { // Test default cursor await tester.pumpWidget( MaterialApp( + theme: theme, home: Scaffold( body: Align( alignment: Alignment.topLeft, @@ -742,8 +795,9 @@ void main() { // Test default cursor when disabled await tester.pumpWidget( - const MaterialApp( - home: Scaffold( + MaterialApp( + theme: theme, + home: const Scaffold( body: Align( alignment: Alignment.topLeft, child: Material( @@ -764,8 +818,9 @@ void main() { // Test cursor when tristate await tester.pumpWidget( - const MaterialApp( - home: Scaffold( + MaterialApp( + theme: theme, + home: const Scaffold( body: Align( alignment: Alignment.topLeft, child: Material( @@ -807,7 +862,7 @@ void main() { Widget buildFrame({required bool enabled}) { return Material( child: Theme( - data: ThemeData(), + data: theme, child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return Checkbox( @@ -856,7 +911,7 @@ void main() { Widget buildFrame() { return Material( child: Theme( - data: ThemeData(), + data: theme, child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return Checkbox( @@ -901,6 +956,7 @@ void main() { Widget buildApp() { return MaterialApp( + theme: theme, home: Material( child: Center( child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { @@ -932,6 +988,82 @@ void main() { ); }); + testWidgets('Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + + final ColorScheme colors = theme.colorScheme; + final bool material3 = theme.useMaterial3; + Widget buildCheckbox({bool active = false, bool focused = false}) { + return MaterialApp( + theme: theme, + home: Scaffold( + body: Checkbox( + focusNode: focusNode, + autofocus: focused, + value: active, + onChanged: (_) { }, + ), + ), + ); + } + + await tester.pumpWidget(buildCheckbox()); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + material3 + ? (paints..circle(color: colors.primary.withOpacity(0.12))) + : (paints + ..circle(color: theme.unselectedWidgetColor.withAlpha(kRadialReactionAlpha),) + ), + reason: 'Default inactive pressed Checkbox should have overlay color from default fillColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + material3 + ? (paints..circle(color: colors.onSurface.withOpacity(0.12))) + : (paints + ..circle(color: colors.secondary.withAlpha(kRadialReactionAlpha),) + ), + reason: 'Default active pressed Checkbox should have overlay color from default fillColor', + ); + + await tester.pumpWidget(buildCheckbox(focused: true)); + await tester.pumpAndSettle(); + + expect(focusNode.hasPrimaryFocus, isTrue); + expect( + Material.of(tester.element(find.byType(Checkbox))), + material3 + ? (paints..circle(color: colors.onSurface.withOpacity(0.12))) + : (paints..circle(color: theme.focusColor)), + reason: 'Focused Checkbox should use default focused overlay color', + ); + + await tester.pumpWidget(Container()); // reset test + await tester.pumpWidget(buildCheckbox()); + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + material3 + ? (paints..circle(color: colors.onSurface.withOpacity(0.08))) + : (paints..circle(color: theme.hoverColor)), + reason: 'Hovered Checkbox should use default hovered overlay color', + ); + }); + testWidgets('Checkbox overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -963,6 +1095,7 @@ void main() { Widget buildCheckbox({bool active = false, bool focused = false, bool useOverlay = true}) { return MaterialApp( + theme: theme, home: Scaffold( body: Checkbox( focusNode: focusNode, @@ -1085,6 +1218,7 @@ void main() { Widget buildTristateCheckbox() { return MaterialApp( + theme: theme, home: Scaffold( body: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { @@ -1175,6 +1309,7 @@ void main() { testWidgets('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { Widget buildCheckbox(bool show) { return MaterialApp( + theme: theme, home: Material( child: Center( child: show ? Checkbox(value: true, onChanged: (_) { }) : Container(), @@ -1205,6 +1340,7 @@ void main() { Widget buildApp({ bool? value, bool enabled = true }) { return MaterialApp( + theme: theme, home: Material( child: Center( child: Checkbox( @@ -1268,6 +1404,7 @@ void main() { Widget buildApp({ bool? value, bool enabled = true }) { return MaterialApp( + theme: theme, home: Material( child: Center( child: Checkbox( @@ -1310,6 +1447,57 @@ void main() { await tester.pumpAndSettle(); expectBorder(); }); + + testWidgets('disabled checkbox shows tooltip', (WidgetTester tester) async { + const String longPressTooltip = 'long press tooltip'; + const String tapTooltip = 'tap tooltip'; + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + message: longPressTooltip, + child: Checkbox(value: true, onChanged: null), + ), + ), + ) + ); + + // Default tooltip shows up after long pressed. + final Finder tooltip0 = find.byType(Tooltip); + expect(find.text(longPressTooltip), findsNothing); + + await tester.tap(tooltip0); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(longPressTooltip), findsNothing); + + final TestGesture gestureLongPress = await tester.startGesture(tester.getCenter(tooltip0)); + await tester.pump(); + await tester.pump(kLongPressTimeout); + await gestureLongPress.up(); + await tester.pump(); + + expect(find.text(longPressTooltip), findsOneWidget); + + // Tooltip shows up after tapping when set triggerMode to TooltipTriggerMode.tap. + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + triggerMode: TooltipTriggerMode.tap, + message: tapTooltip, + child: Checkbox(value: true, onChanged: null), + ), + ), + ) + ); + + final Finder tooltip1 = find.byType(Tooltip); + expect(find.text(tapTooltip), findsNothing); + + await tester.tap(tooltip1); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(tapTooltip), findsOneWidget); + }); } class _SelectedGrabMouseCursor extends MaterialStateMouseCursor { diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 8ce03453c58cd..7202ce7423093 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -250,19 +250,19 @@ void main() { TextStyle labelStyle = getLabelStyle(tester, 'Chip A').style; expect(labelStyle.color?.value, 0xde000000); - expect(labelStyle.fontFamily, textTheme.bodyText1?.fontFamily); - expect(labelStyle.fontFamilyFallback, textTheme.bodyText1?.fontFamilyFallback); - expect(labelStyle.fontFeatures, textTheme.bodyText1?.fontFeatures); - expect(labelStyle.fontSize, textTheme.bodyText1?.fontSize); - expect(labelStyle.fontStyle, textTheme.bodyText1?.fontStyle); - expect(labelStyle.fontWeight, textTheme.bodyText1?.fontWeight); - expect(labelStyle.height, textTheme.bodyText1?.height); - expect(labelStyle.inherit, textTheme.bodyText1?.inherit); - expect(labelStyle.leadingDistribution, textTheme.bodyText1?.leadingDistribution); - expect(labelStyle.letterSpacing, textTheme.bodyText1?.letterSpacing); - expect(labelStyle.overflow, textTheme.bodyText1?.overflow); - expect(labelStyle.textBaseline, textTheme.bodyText1?.textBaseline); - expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing); + expect(labelStyle.fontFamily, textTheme.bodyLarge?.fontFamily); + expect(labelStyle.fontFamilyFallback, textTheme.bodyLarge?.fontFamilyFallback); + expect(labelStyle.fontFeatures, textTheme.bodyLarge?.fontFeatures); + expect(labelStyle.fontSize, textTheme.bodyLarge?.fontSize); + expect(labelStyle.fontStyle, textTheme.bodyLarge?.fontStyle); + expect(labelStyle.fontWeight, textTheme.bodyLarge?.fontWeight); + expect(labelStyle.height, textTheme.bodyLarge?.height); + expect(labelStyle.inherit, textTheme.bodyLarge?.inherit); + expect(labelStyle.leadingDistribution, textTheme.bodyLarge?.leadingDistribution); + expect(labelStyle.letterSpacing, textTheme.bodyLarge?.letterSpacing); + expect(labelStyle.overflow, textTheme.bodyLarge?.overflow); + expect(labelStyle.textBaseline, textTheme.bodyLarge?.textBaseline); + expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing); await tester.pumpWidget(buildFrame(Brightness.dark)); await tester.pumpAndSettle(); // Theme transition animation @@ -277,19 +277,19 @@ void main() { labelStyle = getLabelStyle(tester, 'Chip A').style; expect(labelStyle.color?.value, 0xdeffffff); - expect(labelStyle.fontFamily, textTheme.bodyText1?.fontFamily); - expect(labelStyle.fontFamilyFallback, textTheme.bodyText1?.fontFamilyFallback); - expect(labelStyle.fontFeatures, textTheme.bodyText1?.fontFeatures); - expect(labelStyle.fontSize, textTheme.bodyText1?.fontSize); - expect(labelStyle.fontStyle, textTheme.bodyText1?.fontStyle); - expect(labelStyle.fontWeight, textTheme.bodyText1?.fontWeight); - expect(labelStyle.height, textTheme.bodyText1?.height); - expect(labelStyle.inherit, textTheme.bodyText1?.inherit); - expect(labelStyle.leadingDistribution, textTheme.bodyText1?.leadingDistribution); - expect(labelStyle.letterSpacing, textTheme.bodyText1?.letterSpacing); - expect(labelStyle.overflow, textTheme.bodyText1?.overflow); - expect(labelStyle.textBaseline, textTheme.bodyText1?.textBaseline); - expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing); + expect(labelStyle.fontFamily, textTheme.bodyLarge?.fontFamily); + expect(labelStyle.fontFamilyFallback, textTheme.bodyLarge?.fontFamilyFallback); + expect(labelStyle.fontFeatures, textTheme.bodyLarge?.fontFeatures); + expect(labelStyle.fontSize, textTheme.bodyLarge?.fontSize); + expect(labelStyle.fontStyle, textTheme.bodyLarge?.fontStyle); + expect(labelStyle.fontWeight, textTheme.bodyLarge?.fontWeight); + expect(labelStyle.height, textTheme.bodyLarge?.height); + expect(labelStyle.inherit, textTheme.bodyLarge?.inherit); + expect(labelStyle.leadingDistribution, textTheme.bodyLarge?.leadingDistribution); + expect(labelStyle.letterSpacing, textTheme.bodyLarge?.letterSpacing); + expect(labelStyle.overflow, textTheme.bodyLarge?.overflow); + expect(labelStyle.textBaseline, textTheme.bodyLarge?.textBaseline); + expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing); }); testWidgets('Chip control test', (WidgetTester tester) async { @@ -1767,7 +1767,7 @@ void main() { final ChipThemeData defaultChipTheme = ChipThemeData.fromDefaults( brightness: themeData.brightness, secondaryColor: Colors.blue, - labelStyle: themeData.textTheme.bodyText1!, + labelStyle: themeData.textTheme.bodyLarge!, ); bool value = false; Widget buildApp({ diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index ec0a8f22321bb..2b63f4adc1fe0 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -119,8 +119,8 @@ void main() { 'checkMarkColor: Color(0xfffffff7)', 'labelPadding: EdgeInsets.all(1.0)', 'padding: EdgeInsets.all(2.0)', - 'side: BorderSide(Color(0xff000000), 10.0, BorderStyle.solid)', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', + 'side: BorderSide(width: 10.0)', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'labelStyle: TextStyle(inherit: true, size: 10.0)', 'secondaryLabelStyle: TextStyle(inherit: true, size: 20.0)', 'brightness: dark', @@ -327,7 +327,7 @@ void main() { testWidgets('ChipThemeData generates correct opacities for defaults', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); - final TextStyle customStyle = ThemeData.fallback().textTheme.bodyText1!.copyWith(color: customColor2); + final TextStyle customStyle = ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: customColor2); final ChipThemeData lightTheme = ChipThemeData.fromDefaults( secondaryColor: customColor1, @@ -391,7 +391,7 @@ void main() { final ChipThemeData chipThemeBlack = ChipThemeData.fromDefaults( secondaryColor: Colors.black, brightness: Brightness.dark, - labelStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: Colors.black), + labelStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: Colors.black), ).copyWith( elevation: 1.0, labelPadding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -407,7 +407,7 @@ void main() { final ChipThemeData chipThemeWhite = ChipThemeData.fromDefaults( secondaryColor: Colors.white, brightness: Brightness.light, - labelStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: Colors.white), + labelStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: Colors.white), ).copyWith( padding: const EdgeInsets.all(2.0), labelPadding: const EdgeInsets.only(top: 8.0, bottom: 8.0), diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index cfeb97742a575..4a7f534807158 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -166,7 +166,7 @@ void main() { expect(decoration.color, equals(theme.primaryColorLight)); final RenderParagraph paragraph = tester.renderObject(find.text('Z')); - expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.headline6!.color)); + expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color)); }); testWidgets('CircleAvatar with dark theme', (WidgetTester tester) async { @@ -191,7 +191,7 @@ void main() { expect(decoration.color, equals(theme.primaryColorDark)); final RenderParagraph paragraph = tester.renderObject(find.text('Z')); - expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.headline6!.color)); + expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color)); }); testWidgets('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index fb3a221c5f84f..055298b9096a4 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -156,12 +156,18 @@ void main() { ' Overlay-[LabeledGlobalKey#00000]\n' ' UnmanagedRestorationScope\n' ' _FocusMarker\n' - ' Semantics\n' - ' FocusScope\n' + ' Focus\n' + ' _FocusMarker\n' + ' Focus\n' + ' _FocusTraversalGroupMarker\n' + ' FocusTraversalGroup\n' ' AbsorbPointer\n' ' Listener\n' ' HeroControllerScope\n' ' Navigator-[GlobalObjectKey _WidgetsAppState#00000]\n' + ' _FocusMarker\n' + ' Semantics\n' + ' FocusScope\n' ' DefaultSelectionStyle\n' ' IconTheme\n' ' IconTheme\n' @@ -329,6 +335,7 @@ void main() { ' PhysicalModel\n' ' AnimatedPhysicalModel\n' ' Material\n' + ' KeyedSubtree-[GlobalKey#00000]\n' ' FractionalTranslation\n' ' SlideTransition\n' ' Listener\n' diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index f71677cf29ec7..165a253bc5d4d 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -48,7 +48,7 @@ RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) // What was the AlertDialog's ButtonBar when many of these tests were written, // is now a Padding widget with an OverflowBar child. The Padding widget's size -// and location match the original ButtonBar's size and location. +// and location match the original ButtonBar's size and location. Finder _findButtonBar() { return find.ancestor(of: find.byType(OverflowBar), matching: find.byType(Padding)).first; } diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index 5666af42daef8..b3018cd0fd600 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -299,7 +299,7 @@ void main() { title: Text(titleText), actions: [ ], ); - final ThemeData theme = ThemeData(textTheme: const TextTheme(headline6: titleTextStyle)); + final ThemeData theme = ThemeData(textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); @@ -347,7 +347,7 @@ void main() { const SimpleDialog dialog = SimpleDialog( title: Text(titleText), ); - final ThemeData theme = ThemeData(textTheme: const TextTheme(headline6: titleTextStyle)); + final ThemeData theme = ThemeData(textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); @@ -398,7 +398,7 @@ void main() { content: Text(contentText), actions: [ ], ); - final ThemeData theme = ThemeData(textTheme: const TextTheme(subtitle1: contentTextStyle)); + final ThemeData theme = ThemeData(textTheme: const TextTheme(titleMedium: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); await tester.tap(find.text('X')); diff --git a/packages/flutter/test/material/drawer_theme_test.dart b/packages/flutter/test/material/drawer_theme_test.dart index df79277ac76b7..da6b9e8293a00 100644 --- a/packages/flutter/test/material/drawer_theme_test.dart +++ b/packages/flutter/test/material/drawer_theme_test.dart @@ -43,7 +43,7 @@ void main() { 'backgroundColor: Color(0x00000099)', 'scrimColor: Color(0x00000098)', 'elevation: 5.0', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'width: 200.0', ]); }); diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index 2f07f0cd459ec..3089c70370b7d 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -399,18 +399,21 @@ void main() { Widget build() { return Directionality( textDirection: TextDirection.ltr, - child: Navigator( - initialRoute: '/', - onGenerateRoute: (RouteSettings settings) { - return MaterialPageRoute( - settings: settings, - builder: (BuildContext context) { - return Material( - child: buildFrame(value: 'one', onChanged: didChangeValue), - ); - }, - ); - }, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: Navigator( + initialRoute: '/', + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + return Material( + child: buildFrame(value: 'one', onChanged: didChangeValue), + ); + }, + ); + }, + ), ), ); } @@ -1326,53 +1329,49 @@ void main() { TestSemantics.rootChild( children: [ TestSemantics( + flags: [ + SemanticsFlag.scopesRoute, + SemanticsFlag.namesRoute, + ], + label: 'Popup menu', children: [ TestSemantics( - flags: [ - SemanticsFlag.scopesRoute, - SemanticsFlag.namesRoute, - ], - label: 'Popup menu', children: [ TestSemantics( + flags: [ + SemanticsFlag.hasImplicitScrolling, + ], children: [ TestSemantics( + label: 'one', + textDirection: TextDirection.ltr, flags: [ - SemanticsFlag.hasImplicitScrolling, - ], - children: [ - TestSemantics( - label: 'one', - textDirection: TextDirection.ltr, - flags: [ - SemanticsFlag.isFocused, - SemanticsFlag.isFocusable, - ], - tags: [const SemanticsTag('RenderViewport.twoPane')], - actions: [SemanticsAction.tap], - ), - TestSemantics( - label: 'two', - textDirection: TextDirection.ltr, - flags: [SemanticsFlag.isFocusable], - tags: [const SemanticsTag('RenderViewport.twoPane')], - actions: [SemanticsAction.tap], - ), - TestSemantics( - label: 'three', - textDirection: TextDirection.ltr, - flags: [SemanticsFlag.isFocusable], - tags: [const SemanticsTag('RenderViewport.twoPane')], - actions: [SemanticsAction.tap], - ), - TestSemantics( - label: 'four', - textDirection: TextDirection.ltr, - flags: [SemanticsFlag.isFocusable], - tags: [const SemanticsTag('RenderViewport.twoPane')], - actions: [SemanticsAction.tap], - ), + SemanticsFlag.isFocused, + SemanticsFlag.isFocusable, ], + tags: [const SemanticsTag('RenderViewport.twoPane')], + actions: [SemanticsAction.tap], + ), + TestSemantics( + label: 'two', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isFocusable], + tags: [const SemanticsTag('RenderViewport.twoPane')], + actions: [SemanticsAction.tap], + ), + TestSemantics( + label: 'three', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isFocusable], + tags: [const SemanticsTag('RenderViewport.twoPane')], + actions: [SemanticsAction.tap], + ), + TestSemantics( + label: 'four', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isFocusable], + tags: [const SemanticsTag('RenderViewport.twoPane')], + actions: [SemanticsAction.tap], ), ], ), @@ -1380,7 +1379,6 @@ void main() { ), ], ), - TestSemantics(), ], ), ], diff --git a/packages/flutter/test/material/expansion_tile_test.dart b/packages/flutter/test/material/expansion_tile_test.dart index 8c4cd5a277d10..36bdf9e55de8f 100644 --- a/packages/flutter/test/material/expansion_tile_test.dart +++ b/packages/flutter/test/material/expansion_tile_test.dart @@ -164,7 +164,7 @@ void main() { theme: ThemeData( colorScheme: ColorScheme.fromSwatch().copyWith(primary: foregroundColor), unselectedWidgetColor: unselectedWidgetColor, - textTheme: const TextTheme(subtitle1: TextStyle(color: headerColor)), + textTheme: const TextTheme(titleMedium: TextStyle(color: headerColor)), ), home: Material( child: SingleChildScrollView( diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart new file mode 100644 index 0000000000000..f91e7a05625c0 --- /dev/null +++ b/packages/flutter/test/material/filled_button_test.dart @@ -0,0 +1,1752 @@ +// Copyright 2014 The Flutter Authors. 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('FilledButton, FilledButton.icon defaults', (WidgetTester tester) async { + const ColorScheme colorScheme = ColorScheme.light(); + final ThemeData theme = ThemeData.from(colorScheme: colorScheme); + + // Enabled FilledButton + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FilledButton( + onPressed: () { }, + child: const Text('button'), + ), + ), + ), + ); + + final Finder buttonMaterial = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + ); + + Material material = tester.widget(buttonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.primary); + expect(material.elevation, 0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + expect(material.textStyle!.color, colorScheme.onPrimary); + 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(find.ancestor(of: find.text('button'), matching: find.byType(Align))); + expect(align.alignment, Alignment.center); + + final Offset center = tester.getCenter(find.byType(FilledButton)); + await tester.startGesture(center); + await tester.pump(); // start the splash animation + await tester.pump(const Duration(milliseconds: 100)); // splash is underway + + // Enabled FilledButton.icon + final Key iconButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FilledButton.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(iconButtonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.primary); + expect(material.elevation, 0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + expect(material.textStyle!.color, colorScheme.onPrimary); + expect(material.textStyle!.fontFamily, 'Roboto'); + expect(material.textStyle!.fontSize, 14); + expect(material.textStyle!.fontWeight, FontWeight.w500); + expect(material.type, MaterialType.button); + + // Disabled FilledButton + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Center( + child: FilledButton( + onPressed: null, + child: Text('button'), + ), + ), + ), + ); + + // Finish the elevation animation, final background color change. + await tester.pumpAndSettle(); + + material = tester.widget(buttonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.onSurface.withOpacity(0.12)); + expect(material.elevation, 0.0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + 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('FilledButton.tonal, FilledButton.tonalIcon defaults', (WidgetTester tester) async { + const ColorScheme colorScheme = ColorScheme.light(); + final ThemeData theme = ThemeData.from(colorScheme: colorScheme); + + // Enabled FilledButton + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FilledButton.tonal( + onPressed: () { }, + child: const Text('button'), + ), + ), + ), + ); + + final Finder buttonMaterial = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + ); + + Material material = tester.widget(buttonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.secondaryContainer); + expect(material.elevation, 0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + expect(material.textStyle!.color, colorScheme.onSecondaryContainer); + 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(find.ancestor(of: find.text('button'), matching: find.byType(Align))); + expect(align.alignment, Alignment.center); + + final Offset center = tester.getCenter(find.byType(FilledButton)); + await tester.startGesture(center); + await tester.pump(); // start the splash animation + await tester.pump(const Duration(milliseconds: 100)); // splash is underway + + // Enabled FilledButton.tonalIcon + final Key iconButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FilledButton.tonalIcon( + 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(iconButtonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.secondaryContainer); + expect(material.elevation, 0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + expect(material.textStyle!.color, colorScheme.onSecondaryContainer); + expect(material.textStyle!.fontFamily, 'Roboto'); + expect(material.textStyle!.fontSize, 14); + expect(material.textStyle!.fontWeight, FontWeight.w500); + expect(material.type, MaterialType.button); + + // Disabled FilledButton + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Center( + child: FilledButton.tonal( + onPressed: null, + child: Text('button'), + ), + ), + ), + ); + + // Finish the elevation animation, final background color change. + await tester.pumpAndSettle(); + + material = tester.widget(buttonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderOnForeground, true); + expect(material.borderRadius, null); + expect(material.clipBehavior, Clip.none); + expect(material.color, colorScheme.onSurface.withOpacity(0.12)); + expect(material.elevation, 0.0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + 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('Default FilledButton 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: FilledButton( + onPressed: () { }, + focusNode: focusNode, + child: const Text('FilledButton'), + ), + ), + ), + ), + ); + + // 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(FilledButton)); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(center); + await tester.pumpAndSettle(); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + }, + skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 + ); + + + testWidgets('FilledButton 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 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: FilledButtonTheme( + data: FilledButtonThemeData( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.resolveWith(getTextColor), + ), + ), + child: Builder( + builder: (BuildContext context) { + return FilledButton( + onPressed: () {}, + focusNode: focusNode, + child: const Text('FilledButton'), + ); + }, + ), + ), + ), + ), + ), + ); + + Color textColor() { + return tester.renderObject(find.text('FilledButton')).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(FilledButton)); + 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('FilledButton 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 getTextColor(Set 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: FilledButtonTheme( + data: FilledButtonThemeData( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.resolveWith(getTextColor), + ), + ), + child: Builder( + builder: (BuildContext context) { + return FilledButton.icon( + key: buttonKey, + icon: const Icon(Icons.add), + label: const Text('FilledButton'), + 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('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + bool wasPressed; + Finder filledButton; + + Widget buildFrame({ VoidCallback? onPressed, VoidCallback? onLongPress }) { + return Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + onPressed: onPressed, + onLongPress: onLongPress, + child: const Text('button'), + ), + ); + } + + // onPressed not null, onLongPress null. + wasPressed = false; + await tester.pumpWidget( + buildFrame(onPressed: () { wasPressed = true; }), + ); + filledButton = find.byType(FilledButton); + expect(tester.widget(filledButton).enabled, true); + await tester.tap(filledButton); + expect(wasPressed, true); + + // onPressed null, onLongPress not null. + wasPressed = false; + await tester.pumpWidget( + buildFrame(onLongPress: () { wasPressed = true; }), + ); + filledButton = find.byType(FilledButton); + expect(tester.widget(filledButton).enabled, true); + await tester.longPress(filledButton); + expect(wasPressed, true); + + // onPressed null, onLongPress null. + await tester.pumpWidget( + buildFrame(), + ); + filledButton = find.byType(FilledButton); + expect(tester.widget(filledButton).enabled, false); + }); + + testWidgets('FilledButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + bool didPressButton = false; + bool didLongPressButton = false; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + onPressed: () { + didPressButton = true; + }, + onLongPress: () { + didLongPressButton = true; + }, + child: const Text('button'), + ), + ), + ); + + final Finder filledButton = find.byType(FilledButton); + expect(tester.widget(filledButton).enabled, true); + + expect(didPressButton, isFalse); + await tester.tap(filledButton); + expect(didPressButton, isTrue); + + expect(didLongPressButton, isFalse); + await tester.longPress(filledButton); + expect(didLongPressButton, isTrue); + }); + + testWidgets("FilledButton response doesn't hover when disabled", (WidgetTester tester) async { + FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; + final FocusNode focusNode = FocusNode(debugLabel: 'FilledButton Focus'); + final GlobalKey childKey = GlobalKey(); + bool hovering = false; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 100, + height: 100, + child: FilledButton( + 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: FilledButton( + focusNode: focusNode, + onHover: (bool value) { hovering = value; }, + onPressed: null, + child: SizedBox(key: childKey), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(focusNode.hasPrimaryFocus, isFalse); + }); + + testWidgets('disabled and hovered FilledButton 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: FilledButton( + onPressed: enabled ? () { } : null, + onHover: (bool value) { + onHoverCount += 1; + hover = value; + }, + child: const Text('FilledButton'), + ), + ), + ), + ); + } + + 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(FilledButton))); + 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 FilledButton 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(FilledButton))); + await tester.pumpAndSettle(); + // We no longer see hover events because the FilledButton 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 FilledButton 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(FilledButton)) - const Offset(1, 1)); + await tester.pumpAndSettle(); + // Moving the mouse a little within the FilledButton doesn't change anything. + expect(onHoverCount, 2); + expect(hover, false); + }); + + testWidgets('Can set FilledButton focus and Can set unFocus.', (WidgetTester tester) async { + final FocusNode node = FocusNode(debugLabel: 'FilledButton Focus'); + bool gotFocus = false; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + 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 FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { + final FocusNode node = FocusNode(debugLabel: 'FilledButton Focus'); + bool gotFocus = false; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + 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('Does FilledButton work with hover', (WidgetTester tester) async { + const Color hoverColor = Color(0xff001122); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.resolveWith((Set states) { + return states.contains(MaterialState.hovered) ? hoverColor : null; + }), + ), + onPressed: () { }, + child: const Text('button'), + ), + ), + ); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(FilledButton))); + await tester.pumpAndSettle(); + + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + expect(inkFeatures, paints..rect(color: hoverColor)); + }); + + testWidgets('Does FilledButton work with focus', (WidgetTester tester) async { + const Color focusColor = Color(0xff001122); + + final FocusNode focusNode = FocusNode(debugLabel: 'FilledButton Node'); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.resolveWith((Set states) { + return states.contains(MaterialState.focused) ? focusColor : null; + }), + ), + 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 FilledButton work with autofocus', (WidgetTester tester) async { + const Color focusColor = Color(0xff001122); + + Color? getOverlayColor(Set states) { + return states.contains(MaterialState.focused) ? focusColor : null; + } + + final FocusNode focusNode = FocusNode(debugLabel: 'FilledButton Node'); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + autofocus: true, + style: ButtonStyle( + overlayColor: MaterialStateProperty.resolveWith(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('Does FilledButton contribute semantics', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: FilledButton( + style: const ButtonStyle( + // Specifying minimumSize to mimic the original minimumSize for + // RaisedButton so that the semantics tree's rect and transform + // match the original version of this test. + minimumSize: MaterialStatePropertyAll(Size(88, 36)), + ), + onPressed: () { }, + child: const Text('ABC'), + ), + ), + ), + ); + + expect(semantics, hasSemantics( + TestSemantics.root( + children: [ + TestSemantics.rootChild( + actions: [ + SemanticsAction.tap, + ], + label: 'ABC', + rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), + transform: Matrix4.translationValues(356.0, 276.0, 0.0), + flags: [ + SemanticsFlag.hasEnabledState, + SemanticsFlag.isButton, + SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable, + ], + ), + ], + ), + ignoreId: true, + )); + + semantics.dispose(); + }); + + testWidgets('FilledButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + const ButtonStyle style = ButtonStyle( + // Specifying minimumSize to mimic the original minimumSize for + // RaisedButton so that the corresponding button size matches + // the original version of this test. + minimumSize: MaterialStatePropertyAll(Size(88, 36)), + ); + + Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { + return Theme( + data: ThemeData(materialTapTargetSize: tapTargetSize), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: FilledButton( + key: key, + style: style, + child: const SizedBox(width: 50.0, height: 8.0), + onPressed: () { }, + ), + ), + ), + ); + } + + final Key key1 = UniqueKey(); + await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1)); + expect(tester.getSize(find.byKey(key1)), const Size(88.0, 48.0)); + + final Key key2 = UniqueKey(); + await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2)); + expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); + }); + + testWidgets('FilledButton has no clip by default', (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FilledButton( + onPressed: () { /* to make sure the button is enabled */ }, + child: const Text('button'), + ), + ), + ); + + expect( + tester.renderObject(find.byType(FilledButton)), + paintsExactlyCountTimes(#clipPath, 0), + ); + }); + + testWidgets('FilledButton responds to density changes.', (WidgetTester tester) async { + const Key key = Key('test'); + const Key childKey = Key('test child'); + + Future buildTest(VisualDensity visualDensity, {bool useText = false}) async { + return tester.pumpWidget( + MaterialApp( + // Test was setup using fonts from Material 2, so make sure we always + // test against englishLike2014. + theme: ThemeData(textTheme: Typography.englishLike2014), + home: Directionality( + textDirection: TextDirection.rtl, + child: Center( + child: FilledButton( + style: ButtonStyle( + visualDensity: visualDensity, + // Specifying minimumSize to mimic the original minimumSize for + // RaisedButton so that the corresponding button size matches + // the original version of this test. + minimumSize: const MaterialStatePropertyAll(Size(88, 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))); + }); + + testWidgets('FilledButton.icon responds to applied padding', (WidgetTester tester) async { + const Key buttonKey = Key('test'); + const Key labelKey = Key('label'); + await tester.pumpWidget( + // When textDirection is set to TextDirection.ltr, the label appears on the + // right side of the icon. This is important in determining whether the + // horizontal padding is applied correctly later on + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: FilledButton.icon( + key: buttonKey, + style: const ButtonStyle( + padding: MaterialStatePropertyAll(EdgeInsets.fromLTRB(16, 5, 10, 12)), + ), + onPressed: () {}, + icon: const Icon(Icons.add), + label: const Text( + 'Hello', + key: labelKey, + ), + ), + ), + ), + ); + + final Rect paddingRect = tester.getRect(find.byType(Padding)); + final Rect labelRect = tester.getRect(find.byKey(labelKey)); + final Rect iconRect = tester.getRect(find.byType(Icon)); + + // The right padding should be applied on the right of the label, whereas the + // left padding should be applied on the left side of the icon. + expect(paddingRect.right, labelRect.right + 10); + expect(paddingRect.left, iconRect.left - 16); + // Use the taller widget to check the top and bottom padding. + final Rect tallerWidget = iconRect.height > labelRect.height ? iconRect : labelRect; + expect(paddingRect.top, tallerWidget.top - 5); + expect(paddingRect.bottom, tallerWidget.bottom + 12); + }); + + group('Default FilledButton padding for textScaleFactor, textDirection', () { + const ValueKey buttonKey = ValueKey('button'); + const ValueKey labelKey = ValueKey('label'); + const ValueKey iconKey = ValueKey('icon'); + + const List textScaleFactorOptions = [0.5, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0]; + const List textDirectionOptions = [TextDirection.ltr, TextDirection.rtl]; + const List iconOptions = [null, Icon(Icons.add, size: 18, key: iconKey)]; + + // Expected values for each textScaleFactor. + final Map paddingWithoutIconStart = { + 0.5: 16, + 1: 16, + 1.25: 14, + 1.5: 12, + 2: 8, + 2.5: 6, + 3: 4, + 4: 4, + }; + final Map paddingWithoutIconEnd = { + 0.5: 16, + 1: 16, + 1.25: 14, + 1.5: 12, + 2: 8, + 2.5: 6, + 3: 4, + 4: 4, + }; + final Map paddingWithIconStart = { + 0.5: 12, + 1: 12, + 1.25: 11, + 1.5: 10, + 2: 8, + 2.5: 8, + 3: 8, + 4: 8, + }; + final Map paddingWithIconEnd = { + 0.5: 16, + 1: 16, + 1.25: 14, + 1.5: 12, + 2: 8, + 2.5: 6, + 3: 4, + 4: 4, + }; + final Map paddingWithIconGap = { + 0.5: 8, + 1: 8, + 1.25: 7, + 1.5: 6, + 2: 4, + 2.5: 4, + 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 = [ + 'FilledButton, 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, + filledButtonTheme: FilledButtonThemeData( + style: FilledButton.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 + ? FilledButton( + key: buttonKey, + onPressed: () {}, + child: const Text('button', key: labelKey), + ) + : FilledButton.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 expectedStart = icon != null + ? paddingWithIconStart[textScaleFactor]! + : paddingWithoutIconStart[textScaleFactor]!; + final double expectedEnd = icon != null + ? paddingWithIconEnd[textScaleFactor]! + : paddingWithoutIconEnd[textScaleFactor]!; + final EdgeInsets expectedPadding = EdgeInsetsDirectional.fromSTEB(expectedStart, 0, expectedEnd, 0) + .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(find.byKey(labelKey)); + final Rect labelBounds = globalBounds(labelRenderBox); + final RenderBox? iconRenderBox = icon == null ? null : tester.renderObject(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( + 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( + 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 FilledButton 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: FilledButton( + style: FilledButton.styleFrom(padding: const EdgeInsets.all(22)), + onPressed: () {}, + child: const Text('FilledButton'), + ), + ), + ), + ); + }, + ), + ), + ); + + final Padding paddingWidget = tester.widget( + find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Padding), + ), + ); + expect(paddingWidget.padding, const EdgeInsets.all(22)); + }); + + testWidgets('By default, FilledButton shape outline is defined by shape.side', (WidgetTester tester) async { + const Color borderColor = Color(0xff4caf50); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(colorScheme: const ColorScheme.light(), textTheme: Typography.englishLike2014), + home: Center( + child: FilledButton( + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + side: BorderSide(width: 10, color: borderColor), + ), + minimumSize: const Size(64, 36), + ), + onPressed: () {}, + child: const Text('button'), + ), + ), + ), + ); + + expect(find.byType(FilledButton), paints ..drrect( + // Outer and inner rect that give the outline a width of 10. + outer: RRect.fromLTRBR(0.0, 0.0, 116.0, 36.0, const Radius.circular(16)), + inner: RRect.fromLTRBR(10.0, 10.0, 106.0, 26.0, const Radius.circular(16 - 10)), + color: borderColor) + ); + }); + + testWidgets('Fixed size FilledButtons', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton( + style: FilledButton.styleFrom(fixedSize: const Size(100, 100)), + onPressed: () {}, + child: const Text('100x100'), + ), + FilledButton( + style: FilledButton.styleFrom(fixedSize: const Size.fromWidth(200)), + onPressed: () {}, + child: const Text('200xh'), + ), + FilledButton( + style: FilledButton.styleFrom(fixedSize: const Size.fromHeight(200)), + onPressed: () {}, + child: const Text('wx200'), + ), + ], + ), + ), + ), + ); + + expect(tester.getSize(find.widgetWithText(FilledButton, '100x100')), const Size(100, 100)); + expect(tester.getSize(find.widgetWithText(FilledButton, '200xh')).width, 200); + expect(tester.getSize(find.widgetWithText(FilledButton, 'wx200')).height, 200); + }); + + testWidgets('FilledButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { + return MaterialApp( + home: Scaffold( + body: Center( + child: FilledButton( + style: FilledButton.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('FilledButton 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: FilledButton( + onPressed: () { }, + child: const Text('button'), + ), + ), + ), + ); + + final InkWell buttonInkWell = tester.widget(find.descendant( + of: find.byType(FilledButton), + 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('FilledButton.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: FilledButton.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('FilledButton.icon icon,label layout', (WidgetTester tester) async { + final Key buttonKey = UniqueKey(); + final Key iconKey = UniqueKey(); + final Key labelKey = UniqueKey(); + final ButtonStyle style = FilledButton.styleFrom( + padding: EdgeInsets.zero, + visualDensity: VisualDensity.standard, // dx=0, dy=0 + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + child: FilledButton.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('FilledButton 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: [ + FilledButton( + key: key0, + style: TextButton.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'), + ), + FilledButton.icon( + key: key1, + style: TextButton.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 FilledButton, same as minimumSize == maximumSize', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton( + style: FilledButton.styleFrom(fixedSize: const Size(200, 200)), + onPressed: () { }, + child: const Text('200x200'), + ), + FilledButton( + style: FilledButton.styleFrom( + minimumSize: const Size(200, 200), + maximumSize: const Size(200, 200), + ), + onPressed: () { }, + child: const Text('200,200'), + ), + ], + ), + ), + ), + ); + + expect(tester.getSize(find.widgetWithText(FilledButton, '200x200')), const Size(200, 200)); + expect(tester.getSize(find.widgetWithText(FilledButton, '200,200')), const Size(200, 200)); + }); + + testWidgets('FilledButton changes mouse cursor when hovered', (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MouseRegion( + cursor: SystemMouseCursors.forbidden, + child: FilledButton( + style: FilledButton.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: FilledButton( + style: FilledButton.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: FilledButton( + 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: FilledButton( + onPressed: null, + child: Text('button'), + ), + ), + ), + ); + + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + }); + + testWidgets('Ink Response shape matches Material shape', (WidgetTester tester) async { + Widget buildFrame({BorderSide? side}) { + return MaterialApp( + home: Scaffold( + body: Center( + child: FilledButton( + style: FilledButton.styleFrom( + side: side, + shape: const RoundedRectangleBorder( + side: BorderSide( + color: Color(0xff0000ff), + width: 0, + ), + ), + ), + onPressed: () { }, + child: const Text('FilledButton'), + ), + ), + ), + ); + } + + const BorderSide borderSide = BorderSide(width: 10, color: Color(0xff00ff00)); + await tester.pumpWidget(buildFrame(side: borderSide)); + expect( + tester.widget(find.byType(InkWell)).customBorder, + const RoundedRectangleBorder(side: borderSide), + ); + + await tester.pumpWidget(buildFrame()); + await tester.pumpAndSettle(); + expect( + tester.widget(find.byType(InkWell)).customBorder, + const RoundedRectangleBorder( + side: BorderSide( + color: Color(0xff0000ff), + width: 0.0, + ), + ), + ); + }); + + testWidgets('FilledButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: FilledButton( + style: FilledButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: Colors.purple, + ), + onPressed: () {}, + child: const Text('button'), + ), + ), + ), + ); + + final Material material = tester.widget(find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + )); + expect(material.color, Colors.purple); + expect(material.textStyle!.color, Colors.white); + }); + + testWidgets('FilledButton 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: FilledButton( + statesController: controller, + onPressed: () { }, + child: const Text('button'), + ), + ), + ), + ); + + expect(controller.value, {}); + expect(count, 0); + + final Offset center = tester.getCenter(find.byType(FilledButton)); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(center); + await tester.pumpAndSettle(); + + expect(controller.value, {MaterialState.hovered}); + expect(count, 1); + + await gesture.moveTo(Offset.zero); + await tester.pumpAndSettle(); + + expect(controller.value, {}); + expect(count, 2); + + await gesture.moveTo(center); + await tester.pumpAndSettle(); + + expect(controller.value, {MaterialState.hovered}); + expect(count, 3); + + await gesture.down(center); + await tester.pumpAndSettle(); + + expect(controller.value, {MaterialState.hovered, MaterialState.pressed}); + expect(count, 4); + + await gesture.up(); + await tester.pumpAndSettle(); + + expect(controller.value, {MaterialState.hovered}); + expect(count, 5); + + await gesture.moveTo(Offset.zero); + await tester.pumpAndSettle(); + + expect(controller.value, {}); + expect(count, 6); + + await gesture.down(center); + await tester.pumpAndSettle(); + expect(controller.value, {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: FilledButton( + statesController: controller, + onPressed: null, + child: const Text('button'), + ), + ), + ), + ); + await tester.pumpAndSettle(); + expect(controller.value, {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.disabled}); + expect(count, 11); + await gesture.removePointer(); + }); + + testWidgets('Disabled FilledButton 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: FilledButton( + statesController: controller, + onPressed: null, + child: const Text('button'), + ), + ), + ), + ); + expect(controller.value, {MaterialState.disabled}); + expect(count, 1); + }); + +} + +TextStyle _iconStyle(WidgetTester tester, IconData icon) { + final RichText iconRichText = tester.widget( + find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)), + ); + return iconRichText.text.style!; +} diff --git a/packages/flutter/test/material/filled_button_theme_test.dart b/packages/flutter/test/material/filled_button_theme_test.dart new file mode 100644 index 0000000000000..f793ac43d9cd1 --- /dev/null +++ b/packages/flutter/test/material/filled_button_theme_test.dart @@ -0,0 +1,253 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Passing no FilledButtonTheme returns defaults', (WidgetTester tester) async { + const ColorScheme colorScheme = ColorScheme.light(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.from(colorScheme: colorScheme), + home: Scaffold( + body: Center( + child: FilledButton( + onPressed: () { }, + child: const Text('button'), + ), + ), + ), + ), + ); + + final Finder buttonMaterial = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + ); + + final Material material = tester.widget(buttonMaterial); + expect(material.animationDuration, const Duration(milliseconds: 200)); + expect(material.borderRadius, null); + expect(material.color, colorScheme.primary); + expect(material.elevation, 0); + expect(material.shadowColor, const Color(0xff000000)); + expect(material.shape, const StadiumBorder()); + expect(material.textStyle!.color, colorScheme.onPrimary); + expect(material.textStyle!.fontFamily, 'Roboto'); + expect(material.textStyle!.fontSize, 14); + expect(material.textStyle!.fontWeight, FontWeight.w500); + + final Align align = tester.firstWidget(find.ancestor(of: find.text('button'), matching: find.byType(Align))); + expect(align.alignment, Alignment.center); + }); + + group('[Theme, TextTheme, FilledButton style overrides]', () { + const Color foregroundColor = Color(0xff000001); + const Color backgroundColor = Color(0xff000002); + const Color disabledForegroundColor = Color(0xff000003); + const Color disabledBackgroundColor = Color(0xff000004); + const Color shadowColor = Color(0xff000005); + const double elevation = 1; + const TextStyle textStyle = TextStyle(fontSize: 12.0); + const EdgeInsets padding = EdgeInsets.all(3); + const Size minimumSize = Size(200, 200); + const BorderSide side = BorderSide(color: Colors.green, width: 2); + const OutlinedBorder shape = RoundedRectangleBorder(side: side, borderRadius: BorderRadius.all(Radius.circular(2))); + const MouseCursor enabledMouseCursor = SystemMouseCursors.text; + const MouseCursor disabledMouseCursor = SystemMouseCursors.grab; + const MaterialTapTargetSize tapTargetSize = MaterialTapTargetSize.shrinkWrap; + const Duration animationDuration = Duration(milliseconds: 25); + const bool enableFeedback = false; + const AlignmentGeometry alignment = Alignment.centerLeft; + + final ButtonStyle style = FilledButton.styleFrom( + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + disabledForegroundColor: disabledForegroundColor, + disabledBackgroundColor: disabledBackgroundColor, + shadowColor: shadowColor, + elevation: elevation, + textStyle: textStyle, + padding: padding, + minimumSize: minimumSize, + side: side, + shape: shape, + enabledMouseCursor: enabledMouseCursor, + disabledMouseCursor: disabledMouseCursor, + tapTargetSize: tapTargetSize, + animationDuration: animationDuration, + enableFeedback: enableFeedback, + alignment: alignment, + ); + + Widget buildFrame({ ButtonStyle? buttonStyle, ButtonStyle? themeStyle, ButtonStyle? overallStyle }) { + final Widget child = Builder( + builder: (BuildContext context) { + return FilledButton( + style: buttonStyle, + onPressed: () { }, + child: const Text('button'), + ); + }, + ); + return MaterialApp( + theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( + filledButtonTheme: FilledButtonThemeData(style: overallStyle), + ), + home: Scaffold( + body: Center( + // If the FilledButtonTheme widget is present, it's used + // instead of the Theme's ThemeData.FilledButtonTheme. + child: themeStyle == null ? child : FilledButtonTheme( + data: FilledButtonThemeData(style: themeStyle), + child: child, + ), + ), + ), + ); + } + + final Finder findMaterial = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + ); + + final Finder findInkWell = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(InkWell), + ); + + const Set enabled = {}; + const Set disabled = { MaterialState.disabled }; + const Set hovered = { MaterialState.hovered }; + const Set focused = { MaterialState.focused }; + const Set pressed = { MaterialState.pressed }; + + void checkButton(WidgetTester tester) { + final Material material = tester.widget(findMaterial); + final InkWell inkWell = tester.widget(findInkWell); + expect(material.textStyle!.color, foregroundColor); + expect(material.textStyle!.fontSize, 12); + expect(material.color, backgroundColor); + expect(material.shadowColor, shadowColor); + expect(material.elevation, elevation); + expect(MaterialStateProperty.resolveAs(inkWell.mouseCursor!, enabled), enabledMouseCursor); + expect(MaterialStateProperty.resolveAs(inkWell.mouseCursor!, disabled), disabledMouseCursor); + expect(inkWell.overlayColor!.resolve(hovered), foregroundColor.withOpacity(0.08)); + expect(inkWell.overlayColor!.resolve(focused), foregroundColor.withOpacity(0.12)); + expect(inkWell.overlayColor!.resolve(pressed), foregroundColor.withOpacity(0.12)); + expect(inkWell.enableFeedback, enableFeedback); + expect(material.borderRadius, null); + expect(material.shape, shape); + expect(material.animationDuration, animationDuration); + expect(tester.getSize(find.byType(FilledButton)), const Size(200, 200)); + final Align align = tester.firstWidget(find.ancestor(of: find.text('button'), matching: find.byType(Align))); + expect(align.alignment, alignment); + } + + testWidgets('Button style overrides defaults', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(buttonStyle: style)); + await tester.pumpAndSettle(); // allow the animations to finish + checkButton(tester); + }); + + testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(themeStyle: style)); + await tester.pumpAndSettle(); + checkButton(tester); + }); + + testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(overallStyle: style)); + await tester.pumpAndSettle(); + checkButton(tester); + }); + + // Same as the previous tests with empty ButtonStyle's instead of null. + + testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); + await tester.pumpAndSettle(); // allow the animations to finish + checkButton(tester); + }); + + testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); + await tester.pumpAndSettle(); // allow the animations to finish + checkButton(tester); + }); + + testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); + await tester.pumpAndSettle(); // allow the animations to finish + checkButton(tester); + }); + }); + + testWidgets('Theme shadowColor', (WidgetTester tester) async { + const ColorScheme colorScheme = ColorScheme.light(); + const Color shadowColor = Color(0xff000001); + const Color overriddenColor = Color(0xff000002); + + Widget buildFrame({ Color? overallShadowColor, Color? themeShadowColor, Color? shadowColor }) { + return MaterialApp( + theme: ThemeData.from(colorScheme: colorScheme).copyWith( + shadowColor: overallShadowColor, + ), + home: Scaffold( + body: Center( + child: FilledButtonTheme( + data: FilledButtonThemeData( + style: FilledButton.styleFrom( + shadowColor: themeShadowColor, + ), + ), + child: Builder( + builder: (BuildContext context) { + return FilledButton( + style: FilledButton.styleFrom( + shadowColor: shadowColor, + ), + onPressed: () { }, + child: const Text('button'), + ); + }, + ), + ), + ), + ), + ); + } + + final Finder buttonMaterialFinder = find.descendant( + of: find.byType(FilledButton), + matching: find.byType(Material), + ); + + await tester.pumpWidget(buildFrame()); + Material material = tester.widget(buttonMaterialFinder); + expect(material.shadowColor, Colors.black); //default + + await tester.pumpWidget(buildFrame(themeShadowColor: shadowColor)); + await tester.pumpAndSettle(); // theme animation + material = tester.widget(buttonMaterialFinder); + expect(material.shadowColor, shadowColor); + + await tester.pumpWidget(buildFrame(shadowColor: shadowColor)); + await tester.pumpAndSettle(); // theme animation + material = tester.widget(buttonMaterialFinder); + expect(material.shadowColor, shadowColor); + + await tester.pumpWidget(buildFrame(overallShadowColor: overriddenColor, themeShadowColor: shadowColor)); + await tester.pumpAndSettle(); // theme animation + material = tester.widget(buttonMaterialFinder); + expect(material.shadowColor, shadowColor); + + await tester.pumpWidget(buildFrame(themeShadowColor: overriddenColor, shadowColor: shadowColor)); + await tester.pumpAndSettle(); // theme animation + material = tester.widget(buttonMaterialFinder); + expect(material.shadowColor, shadowColor); + }); +} diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 87274e1d94b25..a0147b9bbffe1 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -607,6 +607,58 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); + + testWidgets('Animator can be updated', (WidgetTester tester) async { + FloatingActionButtonAnimator fabAnimator = FloatingActionButtonAnimator.scaling; + FloatingActionButtonLocation fabLocation = FloatingActionButtonLocation.startFloat; + + final Duration animationDuration = kFloatingActionButtonSegue * 2; + + await tester.pumpWidget(_singleFabScaffold( + fabLocation, + animator: fabAnimator, + )); + + expect(find.byType(FloatingActionButton), findsOneWidget); + expect(tester.binding.transientCallbackCount, 0); + expect(tester.getCenter(find.byType(FloatingActionButton)).dx, 44.0); + + fabLocation = FloatingActionButtonLocation.endFloat; + await tester.pumpWidget(_singleFabScaffold( + fabLocation, + animator: fabAnimator, + )); + + expect(tester.getTopLeft(find.byType(FloatingActionButton)).dx, lessThan(16.0)); + + await tester.pump(animationDuration * 0.25); + expect(tester.getTopLeft(find.byType(FloatingActionButton)).dx, greaterThan(16)); + + await tester.pump(animationDuration * 0.25); + expect(tester.getCenter(find.byType(FloatingActionButton)).dx, 756.0); + expect(tester.getTopRight(find.byType(FloatingActionButton)).dx, lessThan(800 - 16)); + + await tester.pump(animationDuration * 0.25); + expect(tester.getTopRight(find.byType(FloatingActionButton)).dx, lessThan(800 - 16)); + + await tester.pump(animationDuration * 0.25); + expect(tester.getTopRight(find.byType(FloatingActionButton)).dx, equals(800 - 16)); + + fabLocation = FloatingActionButtonLocation.startFloat; + fabAnimator = _NoScalingFabAnimator(); + await tester.pumpWidget(_singleFabScaffold( + fabLocation, + animator: fabAnimator, + )); + + await tester.pump(animationDuration * 0.25); + expect(tester.getCenter(find.byType(FloatingActionButton)).dx, 756.0); + expect(tester.getTopRight(find.byType(FloatingActionButton)).dx, equals(800 - 16)); + + await tester.pump(animationDuration * 0.25); + expect(tester.getCenter(find.byType(FloatingActionButton)).dx, 44.0); + expect(tester.getTopLeft(find.byType(FloatingActionButton)).dx, lessThan(16.0)); + }); }); group('Locations account for safe interactive areas', () { @@ -1717,3 +1769,20 @@ class _LinearMovementFabAnimator extends FloatingActionButtonAnimator { return const AlwaysStoppedAnimation(1.0); } } + +class _NoScalingFabAnimator extends FloatingActionButtonAnimator { + @override + Offset getOffset({required Offset begin, required Offset end, required double progress}) { + return progress < 0.5 ? begin : end; + } + + @override + Animation getScaleAnimation({required Animation parent}) { + return const AlwaysStoppedAnimation(1.0); + } + + @override + Animation getRotationAnimation({required Animation parent}) { + return const AlwaysStoppedAnimation(1.0); + } +} diff --git a/packages/flutter/test/material/floating_action_button_theme_test.dart b/packages/flutter/test/material/floating_action_button_theme_test.dart index 1eca03272b3a7..b30c677a53e7e 100644 --- a/packages/flutter/test/material/floating_action_button_theme_test.dart +++ b/packages/flutter/test/material/floating_action_button_theme_test.dart @@ -307,7 +307,7 @@ void main() { 'hoverElevation: 10.0', 'disabledElevation: 11.0', 'highlightElevation: 43.0', - 'shape: BeveledRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', + 'shape: BeveledRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'enableFeedback: true', 'iconSize: 42.0', 'sizeConstraints: BoxConstraints(w=100.0, h=100.0)', diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 9eeb6893d7238..5d65c374fceae 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -282,9 +282,9 @@ void main() { final ThemeData themeDataM3 = ThemeData( useMaterial3: material3, iconButtonTheme: IconButtonThemeData( - style: IconButton.styleFrom( - visualDensity: const VisualDensity(horizontal: 1, vertical: -1) - ) + style: IconButton.styleFrom( + visualDensity: const VisualDensity(horizontal: 1, vertical: -1) + ) ), ); await tester.pumpWidget( @@ -1649,10 +1649,10 @@ void main() { return tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: colorScheme, useMaterial3: true).copyWith( - iconButtonTheme: IconButtonThemeData( - style: IconButton.styleFrom(visualDensity: iconButtonThemeVisualDensity) - ), - visualDensity: themeVisualDensity + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom(visualDensity: iconButtonThemeVisualDensity) + ), + visualDensity: themeVisualDensity ), home: Material( child: Center( diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index 083a72b2c040a..8a52797f923bf 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -9,14 +9,19 @@ import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('The Ink widget renders a Container by default', (WidgetTester tester) async { + testWidgets('The Ink widget renders a SizedBox by default', (WidgetTester tester) async { await tester.pumpWidget( Material( child: Ink(), ), ); - expect(tester.getSize(find.byType(Container)).height, 600.0); - expect(tester.getSize(find.byType(Container)).width, 800.0); + Finder sizedBox = find.descendant( + of: find.byType(Ink), + matching: find.byType(SizedBox), + ); + expect(sizedBox, findsOneWidget); + expect(tester.getSize(sizedBox).height, 600.0); + expect(tester.getSize(sizedBox).width, 800.0); const double height = 150.0; const double width = 200.0; @@ -31,8 +36,13 @@ void main() { ), ); await tester.pumpAndSettle(); - expect(tester.getSize(find.byType(Container)).height, height); - expect(tester.getSize(find.byType(Container)).width, width); + sizedBox = find.descendant( + of: find.byType(Ink), + matching: find.byType(SizedBox), + ); + expect(sizedBox, findsNWidgets(2)); + expect(tester.getSize(sizedBox.at(0)).height, height); + expect(tester.getSize(sizedBox.at(0)).width, width); }); testWidgets('The InkWell widget renders an ink splash', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index db2de05c6ee24..23b3285afe1a9 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -1657,6 +1657,30 @@ void main() { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx)); }); + testWidgets('InputDecorator iconColor/prefixIconColor/suffixIconColor', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: TextField( + decoration: InputDecoration( + icon: Icon(Icons.cabin), + prefixIcon: Icon(Icons.sailing), + suffixIcon: Icon(Icons.close), + iconColor: Colors.amber, + prefixIconColor: Colors.green, + suffixIconColor: Colors.red, + filled: true, + ), + ), + ), + ), + ); + + expect(tester.widget(find.widgetWithIcon(IconTheme,Icons.cabin).first).data.color, Colors.amber); + expect(tester.widget(find.widgetWithIcon(IconTheme,Icons.sailing).first).data.color, Colors.green); + expect(tester.widget(find.widgetWithIcon(IconTheme,Icons.close).first).data.color, Colors.red); + }); + testWidgets('InputDecorator prefix/suffix widgets', (WidgetTester tester) async { const Key pKey = Key('p'); const Key sKey = Key('s'); @@ -2111,7 +2135,7 @@ void main() { ), ); - // Overall height for this InputDecorator is 100dps because the prefix icon's size + // Overall height for this InputDecorator is 100dps because the prefix icon's size // is 100x100 and the rest of the elements only require 40dps: // 12 - top padding // 16 - input text (ahem font size 16dps) @@ -4597,7 +4621,7 @@ void main() { ), ); await tester.pumpAndSettle(); - expect(getBorderColor(tester), theme.errorColor); + expect(getBorderColor(tester), theme.colorScheme.error); // Disabled await tester.pumpWidget( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index 5edd20c4b0870..2066f784d825b 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -1258,6 +1258,30 @@ void main() { ); }); + testWidgets('ListTile can be splashed and has correct splash color', (WidgetTester tester) async { + final Widget buildApp = MaterialApp( + home: Material( + child: Center( + child: SizedBox( + width: 100, + height: 100, + child: ListTile( + onTap: () {}, + splashColor: const Color(0xff88ff88), + ), + ), + ), + ), + ); + + await tester.pumpWidget(buildApp); + await tester.pumpAndSettle(); + final TestGesture gesture = await tester.startGesture(tester.getRect(find.byType(ListTile)).center); + await tester.pump(const Duration(milliseconds: 200)); + expect(find.byType(Material), paints..circle(x: 50, y: 50, color: const Color(0xff88ff88))); + await gesture.up(); + }); + testWidgets('ListTile can be triggered by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Key tileKey = Key('ListTile'); @@ -1993,9 +2017,9 @@ void main() { Color textColor(Key key) => tester.state(find.byKey(key)).textStyle.color!; await tester.pumpWidget(buildFrame()); - // Enabled color should be default bodyText2 color. - expect(textColor(leadingKey), theme.textTheme.bodyText2!.color); - expect(textColor(trailingKey), theme.textTheme.bodyText2!.color); + // Enabled color should be default bodyMedium color. + expect(textColor(leadingKey), theme.textTheme.bodyMedium!.color); + expect(textColor(trailingKey), theme.textTheme.bodyMedium!.color); await tester.pumpWidget(buildFrame(selected: true)); // Wait for text color to animate. @@ -2013,8 +2037,6 @@ void main() { }); testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/pull/77004 - const ColorScheme lightColorScheme = ColorScheme.light(); const ColorScheme darkColorScheme = ColorScheme.dark(); final Key leadingKey = UniqueKey(); @@ -2024,8 +2046,8 @@ void main() { Widget buildFrame({ required Brightness brightness, required bool selected }) { final ThemeData theme = brightness == Brightness.light - ? ThemeData.from(colorScheme: const ColorScheme.light()) - : ThemeData.from(colorScheme: const ColorScheme.dark()); + ? ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true) + : ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: true); return MaterialApp( theme: theme, home: Material( @@ -2051,10 +2073,10 @@ void main() { expect(iconColor(trailingKey), lightColorScheme.primary); await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false)); - expect(iconColor(leadingKey), Colors.black45); - expect(iconColor(titleKey), Colors.black45); - expect(iconColor(subtitleKey), Colors.black45); - expect(iconColor(trailingKey), Colors.black45); + expect(iconColor(leadingKey), lightColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(titleKey), lightColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(subtitleKey), lightColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(trailingKey), lightColorScheme.onSurface.withOpacity(0.38)); await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: true)); await tester.pumpAndSettle(); // Animated theme change @@ -2066,10 +2088,10 @@ void main() { // For this configuration, ListTile defers to the default IconTheme. // The default dark theme's IconTheme has color:white await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: false)); - expect(iconColor(leadingKey), Colors.white); - expect(iconColor(titleKey), Colors.white); - expect(iconColor(subtitleKey), Colors.white); - expect(iconColor(trailingKey), Colors.white); + expect(iconColor(leadingKey), darkColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(titleKey), darkColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(subtitleKey), darkColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(trailingKey), darkColorScheme.onSurface.withOpacity(0.38)); }); testWidgets('ListTile font size', (WidgetTester tester) async { @@ -2262,7 +2284,7 @@ void main() { 'isThreeLine: THREE_LINE', 'dense: true', 'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'style: ListTileStyle.list', 'selectedColor: Color(0xff0000ff)', 'iconColor: Color(0xff00ff00)', @@ -2398,25 +2420,85 @@ void main() { // ListTile - ListTileStyle.list (default). await tester.pumpWidget(buildFrame()); RenderParagraph leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.color, theme.textTheme.bodyText2!.color); + expect(leading.text.style!.color, theme.textTheme.bodyMedium!.color); RenderParagraph title = _getTextRenderObject(tester, 'title'); - expect(title.text.style!.color, theme.textTheme.subtitle1!.color); + expect(title.text.style!.color, theme.textTheme.titleMedium!.color); RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); - expect(subtitle.text.style!.color, theme.textTheme.caption!.color); + expect(subtitle.text.style!.color, theme.textTheme.bodySmall!.color); RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.color, theme.textTheme.bodyText2!.color); + expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color); // ListTile - ListTileStyle.drawer. await tester.pumpWidget(buildFrame(style: ListTileStyle.drawer)); await tester.pumpAndSettle(); leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.color, theme.textTheme.bodyText2!.color); + expect(leading.text.style!.color, theme.textTheme.bodyMedium!.color); title = _getTextRenderObject(tester, 'title'); - expect(title.text.style!.color, theme.textTheme.subtitle1!.color); + expect(title.text.style!.color, theme.textTheme.titleMedium!.color); subtitle = _getTextRenderObject(tester, 'subtitle'); - expect(subtitle.text.style!.color, theme.textTheme.caption!.color); + expect(subtitle.text.style!.color, theme.textTheme.bodySmall!.color); trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.color, theme.textTheme.bodyText2!.color); + expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color); + }); + + testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/pull/77004 + + const ColorScheme lightColorScheme = ColorScheme.light(); + const ColorScheme darkColorScheme = ColorScheme.dark(); + final Key leadingKey = UniqueKey(); + final Key titleKey = UniqueKey(); + final Key subtitleKey = UniqueKey(); + final Key trailingKey = UniqueKey(); + + Widget buildFrame({ required Brightness brightness, required bool selected }) { + final ThemeData theme = brightness == Brightness.light + ? ThemeData.from(colorScheme: const ColorScheme.light()) + : ThemeData.from(colorScheme: const ColorScheme.dark()); + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: ListTile( + selected: selected, + leading: TestIcon(key: leadingKey), + title: TestIcon(key: titleKey), + subtitle: TestIcon(key: subtitleKey), + trailing: TestIcon(key: trailingKey), + ), + ), + ), + ); + } + + Color iconColor(Key key) => tester.state(find.byKey(key)).iconTheme.color!; + + await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: true)); + expect(iconColor(leadingKey), lightColorScheme.primary); + expect(iconColor(titleKey), lightColorScheme.primary); + expect(iconColor(subtitleKey), lightColorScheme.primary); + expect(iconColor(trailingKey), lightColorScheme.primary); + + await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false)); + expect(iconColor(leadingKey), Colors.black45); + expect(iconColor(titleKey), Colors.black45); + expect(iconColor(subtitleKey), Colors.black45); + expect(iconColor(trailingKey), Colors.black45); + + await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: true)); + await tester.pumpAndSettle(); // Animated theme change + expect(iconColor(leadingKey), darkColorScheme.primary); + expect(iconColor(titleKey), darkColorScheme.primary); + expect(iconColor(subtitleKey), darkColorScheme.primary); + expect(iconColor(trailingKey), darkColorScheme.primary); + + // For this configuration, ListTile defers to the default IconTheme. + // The default dark theme's IconTheme has color:white + await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: false)); + expect(iconColor(leadingKey), Colors.white); + expect(iconColor(titleKey), Colors.white); + expect(iconColor(subtitleKey), Colors.white); + expect(iconColor(trailingKey), Colors.white); }); }); } diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index 66fdb094ee37a..89d43e840189b 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -111,7 +111,7 @@ void main() { description, equalsIgnoringHashCodes([ 'dense: true', - 'shape: StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))', + 'shape: StadiumBorder(BorderSide(width: 0.0, style: none))', 'style: drawer', 'selectedColor: Color(0x00000001)', 'iconColor: Color(0x00000002)', diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index bd79843943a5b..055ba4192ae6c 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -46,7 +46,7 @@ void main() { expect(description[1], 'backgroundColor: Color(0x00000099)'); expect(description[2], 'elevation: 20.0'); expect(description[3], 'indicatorColor: Color(0x00000098)'); - expect(description[4], 'indicatorShape: CircleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))'); + expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))'); expect(description[5], 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))'); // Ignore instance address for IconThemeData. diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index fe7a19d5b825a..17eb179b9295a 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -1143,7 +1143,7 @@ void main() { ); // Since the rail is icon only, its preferred width should not be affected - // by textScaleFactor. + // by textScaleFactor. final RenderBox renderBox = tester.renderObject(find.byType(NavigationRail)); expect(renderBox.size.width, compactWidth); @@ -1221,7 +1221,7 @@ void main() { ); // Since the rail is icon only, its preferred width should not be affected - // by textScaleFactor. + // by textScaleFactor. final RenderBox renderBox = tester.renderObject(find.byType(NavigationRail)); expect(renderBox.size.width, compactWidth); @@ -3603,7 +3603,7 @@ void main() { ); // Since the rail is icon only, its preferred width should not be affected - // by textScaleFactor. + // by textScaleFactor. final RenderBox renderBox = tester.renderObject(find.byType(NavigationRail)); expect(renderBox.size.width, 56.0); @@ -3674,7 +3674,7 @@ void main() { ); // Since the rail is icon only, its preferred width should not be affected - // by textScaleFactor. + // by textScaleFactor. final RenderBox renderBox = tester.renderObject(find.byType(NavigationRail)); expect(renderBox.size.width, 56.0); diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index 2a0e86c8c56d0..7c6dc815b60a1 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -158,7 +158,7 @@ void main() { testWidgets('test page transition (_ZoomPageTransition) without rasterization', (WidgetTester tester) async { Iterable findLayers(Finder of) { return tester.layerListOf( - find.ancestor(of: of, matching: find.byType(RasterWidget)).first, + find.ancestor(of: of, matching: find.byType(SnapshotWidget)).first, ); } @@ -174,7 +174,7 @@ void main() { MaterialApp( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute( - preferRasterization: false, + allowSnapshotting: false, builder: (BuildContext context) { if (settings.name == '/') { return const Material(child: Text('Page 1')); @@ -1004,8 +1004,7 @@ void main() { await tester.pumpWidget( RootRestorationScope( restorationId: 'root', - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( onPopPage: (Route route, dynamic result) { return false; }, pages: const >[ @@ -1177,3 +1176,20 @@ class _TestRestorableWidgetState extends State with Restor ); } } + +class TestDependencies extends StatelessWidget { + const TestDependencies({required this.child, super.key}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: child, + ), + ); + } +} diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 61dd0b8ad7f4d..9cc07b955e447 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1773,7 +1773,7 @@ void main() { textDirection: textDirection, child: PopupMenuTheme( data: PopupMenuTheme.of(context).copyWith( - textStyle: Theme.of(context).textTheme.subtitle1!.copyWith(fontSize: fontSize), + textStyle: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: fontSize), ), child: child!, ), diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index 768c5b6b213b1..e719cd58ffefc 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -13,6 +13,7 @@ PopupMenuThemeData _popupMenuTheme() { shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))), elevation: 12.0, textStyle: TextStyle(color: Color(0xffffffff), textBaseline: TextBaseline.alphabetic), + position: PopupMenuPosition.under, ); } @@ -29,6 +30,7 @@ void main() { expect(popupMenuTheme.elevation, null); expect(popupMenuTheme.textStyle, null); expect(popupMenuTheme.mouseCursor, null); + expect(popupMenuTheme.position, null); }); testWidgets('Default PopupMenuThemeData debugFillProperties', (WidgetTester tester) async { @@ -51,6 +53,7 @@ void main() { elevation: 2.0, textStyle: TextStyle(color: Color(0xffffffff)), mouseCursor: MaterialStateMouseCursor.clickable, + position: PopupMenuPosition.over, ).debugFillProperties(builder); final List description = builder.properties @@ -60,10 +63,11 @@ void main() { expect(description, [ 'color: Color(0xffffffff)', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'elevation: 2.0', 'text style: TextStyle(inherit: true, color: Color(0xffffffff))', 'mouseCursor: MaterialStateMouseCursor(clickable)', + 'position: over' ]); }); @@ -78,16 +82,21 @@ void main() { home: Material( child: Column( children: [ - PopupMenuButton( - key: popupButtonKey, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: popupItemKey, - child: const Text('Example'), - ), - ]; - }, + Padding( + // The padding makes sure the menu as enough space to around to + // get properly aligned when displayed (`_kMenuScreenPadding`). + padding: const EdgeInsets.all(8.0), + child: PopupMenuButton( + key: popupButtonKey, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + key: popupItemKey, + child: const Text('Example'), + ), + ]; + }, + ), ), ], ), @@ -123,6 +132,11 @@ void main() { ); expect(text.style.fontFamily, 'Roboto'); expect(text.style.color, const Color(0xdd000000)); + expect(text.style.color, const Color(0xdd000000)); + + final Offset topLeftButton = tester.getTopLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, topLeftButton); }); testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { @@ -138,6 +152,10 @@ void main() { child: Column( children: [ PopupMenuButton( + // The padding is used in the positioning of the menu when the + // position is `PopupMenuPosition.under`. Setting it to zero makes + // it easier to test. + padding: EdgeInsets.zero, key: popupButtonKey, itemBuilder: (BuildContext context) { return >[ @@ -181,6 +199,10 @@ void main() { ).last, ); expect(text.style, popupMenuTheme.textStyle); + + final Offset bottomLeftButton = tester.getBottomLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, bottomLeftButton); }); testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async { @@ -202,20 +224,26 @@ void main() { home: Material( child: Column( children: [ - PopupMenuButton( - key: popupButtonKey, - elevation: elevation, - color: color, - shape: shape, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: popupItemKey, - textStyle: textStyle, - child: const Text('Example'), - ), - ]; - }, + Padding( + // The padding makes sure the menu as enough space to around to + // get properly aligned when displayed (`_kMenuScreenPadding`). + padding: const EdgeInsets.all(8.0), + child: PopupMenuButton( + key: popupButtonKey, + elevation: elevation, + color: color, + shape: shape, + position: PopupMenuPosition.over, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + key: popupItemKey, + textStyle: textStyle, + child: const Text('Example'), + ), + ]; + }, + ), ), ], ), @@ -250,6 +278,10 @@ void main() { ).last, ); expect(text.style, textStyle); + + final Offset topLeftButton = tester.getTopLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, topLeftButton); }); testWidgets('ThemeData.popupMenuTheme properties are utilized', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 33105435cdae8..f3080f8bf6664 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; @@ -1115,4 +1116,55 @@ void main() { // Release pointer after widget disappeared. await gesture.up(); }); + + testWidgets('disabled radio shows tooltip', (WidgetTester tester) async { + const String longPressTooltip = 'long press tooltip'; + const String tapTooltip = 'tap tooltip'; + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + message: longPressTooltip, + child: Radio(value: true, groupValue: false, onChanged: null), + ), + ), + ) + ); + + // Default tooltip shows up after long pressed. + final Finder tooltip0 = find.byType(Tooltip); + expect(find.text(longPressTooltip), findsNothing); + + await tester.tap(tooltip0); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(longPressTooltip), findsNothing); + + final TestGesture gestureLongPress = await tester.startGesture(tester.getCenter(tooltip0)); + await tester.pump(); + await tester.pump(kLongPressTimeout); + await gestureLongPress.up(); + await tester.pump(); + + expect(find.text(longPressTooltip), findsOneWidget); + + // Tooltip shows up after tapping when set triggerMode to TooltipTriggerMode.tap. + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + triggerMode: TooltipTriggerMode.tap, + message: tapTooltip, + child: Radio(value: true, groupValue: false, onChanged: null), + ), + ), + ) + ); + + final Finder tooltip1 = find.byType(Tooltip); + expect(find.text(tapTooltip), findsNothing); + + await tester.tap(tooltip1); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(tapTooltip), findsOneWidget); + }); } diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart index 22c0db79b5260..4793cf7a3ae3b 100644 --- a/packages/flutter/test/material/scaffold_test.dart +++ b/packages/flutter/test/material/scaffold_test.dart @@ -2062,7 +2062,7 @@ void main() { await tester.pumpWidget(buildFrame(false, false)); expect(tester.getSize(find.byKey(bodyKey)), const Size(800.0, 600.0)); - await tester.pumpWidget(buildFrame(null, null)); // resizeToAvoidBottomInset default is true + await tester.pumpWidget(buildFrame(null, null)); // resizeToAvoidBottomInset default is true expect(tester.getSize(find.byKey(bodyKey)), const Size(800.0, 500.0)); await tester.pumpWidget(buildFrame(null, false)); diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart index 629e3e6603603..19f03af5d5415 100644 --- a/packages/flutter/test/material/search_test.dart +++ b/packages/flutter/test/material/search_test.dart @@ -756,7 +756,7 @@ void main() { expect(appBarBackground.color, Colors.white); final TextField textField = tester.widget(find.byType(TextField)); - expect(textField.style!.color, themeData.textTheme.bodyText1!.color); + expect(textField.style!.color, themeData.textTheme.bodyLarge!.color); expect(textField.style!.color, isNot(equals(Colors.white))); }); @@ -784,7 +784,7 @@ void main() { expect(appBarBackground.color, themeData.primaryColor); final TextField textField = tester.widget(find.byType(TextField)); - expect(textField.style!.color, themeData.textTheme.bodyText1!.color); + expect(textField.style!.color, themeData.textTheme.bodyLarge!.color); expect(textField.style!.color, isNot(equals(themeData.primaryColor))); }); diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index c4cb77319cf2b..4c697af43d034 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -4,9 +4,17 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { + const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0); + final Offset localOffset = paragraph.getOffsetForCaret(TextPosition(offset: offset), caret); + return paragraph.localToGlobal(localOffset); +} + void main() { testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -33,4 +41,35 @@ void main() { break; } }, variant: TargetPlatformVariant.all()); + + testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + SelectedContent? content; + + await tester.pumpWidget(MaterialApp( + home: SelectionArea( + child: const Text('How are you'), + onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent, + ), + )); + final RenderParagraph paragraph = tester.renderObject(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 4), kind: PointerDeviceKind.mouse); + expect(content, isNull); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(textOffsetToPosition(paragraph, 7)); + await gesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'are'); + + // Backwards selection. + await gesture.down(textOffsetToPosition(paragraph, 3)); + expect(content, isNull); + await gesture.moveTo(textOffsetToPosition(paragraph, 0)); + await gesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'How'); + }); } diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index ff39275a166ce..6e5768400023e 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -631,6 +631,7 @@ void main() { try { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); + const Color customColor3 = Color(0xdecaface); final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -647,6 +648,8 @@ void main() { overlayColor: Color(0xff000010), thumbColor: Color(0xff000011), valueIndicatorColor: Color(0xff000012), + disabledSecondaryActiveTrackColor: Color(0xff000013), + secondaryActiveTrackColor: Color(0xff000014), ), ); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -654,6 +657,7 @@ void main() { Widget buildApp({ Color? activeColor, Color? inactiveColor, + Color? secondaryActiveColor, int? divisions, bool enabled = true, }) { @@ -671,10 +675,12 @@ void main() { data: theme, child: Slider( value: value, + secondaryTrackValue: 0.75, label: '$value', divisions: divisions, activeColor: activeColor, inactiveColor: inactiveColor, + secondaryActiveColor: secondaryActiveColor, onChanged: onChanged, ), ), @@ -690,47 +696,61 @@ void main() { final RenderBox valueIndicatorBox = tester.renderObject(find.byType(Overlay)); // Check default theme for enabled widget. - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor)); expect(material, paints..shadow(color: const Color(0xff000000))); expect(material, paints..circle(color: sliderTheme.thumbColor)); expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); // Test setting only the activeColor. await tester.pumpWidget(buildApp(activeColor: customColor1)); - expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)); + expect(material, paints..rrect(color: customColor1)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor)); expect(material, paints..shadow(color: Colors.black)); expect(material, paints..circle(color: customColor1)); expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); // Test setting only the inactiveColor. await tester.pumpWidget(buildApp(inactiveColor: customColor1)); - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: customColor1)..rrect(color: sliderTheme.secondaryActiveTrackColor)); expect(material, paints..shadow(color: Colors.black)); expect(material, paints..circle(color: sliderTheme.thumbColor)); expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); - // Test setting both activeColor and inactiveColor. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2)); - expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); + // Test setting only the secondaryActiveColor. + await tester.pumpWidget(buildApp(secondaryActiveColor: customColor1)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: customColor1)); + expect(material, paints..shadow(color: Colors.black)); + expect(material, paints..circle(color: sliderTheme.thumbColor)); + expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); + + // Test setting both activeColor, inactiveColor, and secondaryActiveColor. + await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3)); + expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)..rrect(color: customColor3)); expect(material, paints..shadow(color: Colors.black)); expect(material, paints..circle(color: customColor1)); expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); // Test colors for discrete slider. await tester.pumpWidget(buildApp(divisions: 3)); - expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)); + expect(material, paints..rrect(color: sliderTheme.activeTrackColor)..rrect(color: sliderTheme.inactiveTrackColor)..rrect(color: sliderTheme.secondaryActiveTrackColor)); expect( material, paints @@ -744,14 +764,16 @@ void main() { expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); // Test colors for discrete slider with inactiveColor and activeColor set. await tester.pumpWidget(buildApp( activeColor: customColor1, inactiveColor: customColor2, + secondaryActiveColor: customColor3, divisions: 3, )); - expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)); + expect(material, paints..rrect(color: customColor1)..rrect(color: customColor2)..rrect(color: customColor3)); expect( material, paints @@ -766,6 +788,7 @@ void main() { expect(material, isNot(paints..circle(color: sliderTheme.disabledThumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledActiveTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.disabledInactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor))); expect(material, isNot(paints..circle(color: sliderTheme.activeTickMarkColor))); expect(material, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); @@ -776,25 +799,29 @@ void main() { material, paints ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor), + ..rrect(color: sliderTheme.disabledInactiveTrackColor) + ..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor), ); expect(material, paints..shadow(color: Colors.black)..circle(color: sliderTheme.disabledThumbColor)); expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor))); - // Test setting the activeColor and inactiveColor for disabled widget. - await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, enabled: false)); + // Test setting the activeColor, inactiveColor and secondaryActiveColor for disabled widget. + await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, secondaryActiveColor: customColor3, enabled: false)); expect( material, paints ..rrect(color: sliderTheme.disabledActiveTrackColor) - ..rrect(color: sliderTheme.disabledInactiveTrackColor), + ..rrect(color: sliderTheme.disabledInactiveTrackColor) + ..rrect(color: sliderTheme.disabledSecondaryActiveTrackColor), ); expect(material, paints..circle(color: sliderTheme.disabledThumbColor)); expect(material, isNot(paints..circle(color: sliderTheme.thumbColor))); expect(material, isNot(paints..rrect(color: sliderTheme.activeTrackColor))); expect(material, isNot(paints..rrect(color: sliderTheme.inactiveTrackColor))); + expect(material, isNot(paints..rrect(color: sliderTheme.secondaryActiveTrackColor))); // Test that the default value indicator has the right colors. await tester.pumpWidget(buildApp(divisions: 3)); @@ -2813,10 +2840,12 @@ void main() { activeColor: Colors.blue, divisions: 10, inactiveColor: Colors.grey, + secondaryActiveColor: Colors.blueGrey, label: 'Set a value', max: 100.0, onChanged: null, value: 50.0, + secondaryTrackValue: 75.0, ).debugFillProperties(builder); final List description = builder.properties @@ -2825,6 +2854,7 @@ void main() { expect(description, [ 'value: 50.0', + 'secondaryTrackValue: 75.0', 'disabled', 'min: 0.0', 'max: 100.0', @@ -2832,6 +2862,7 @@ void main() { 'label: "Set a value"', 'activeColor: MaterialColor(primary value: Color(0xff2196f3))', 'inactiveColor: MaterialColor(primary value: Color(0xff9e9e9e))', + 'secondaryActiveColor: MaterialColor(primary value: Color(0xff607d8b))', ]); }); diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 111da30fef01b..e197fb6108444 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -34,17 +34,19 @@ void main() { trackHeight: 7.0, activeTrackColor: Color(0xFF000001), inactiveTrackColor: Color(0xFF000002), - disabledActiveTrackColor: Color(0xFF000003), - disabledInactiveTrackColor: Color(0xFF000004), - activeTickMarkColor: Color(0xFF000005), - inactiveTickMarkColor: Color(0xFF000006), - disabledActiveTickMarkColor: Color(0xFF000007), - disabledInactiveTickMarkColor: Color(0xFF000008), - thumbColor: Color(0xFF000009), - overlappingShapeStrokeColor: Color(0xFF000010), - disabledThumbColor: Color(0xFF000011), - overlayColor: Color(0xFF000012), - valueIndicatorColor: Color(0xFF000013), + secondaryActiveTrackColor: Color(0xFF000003), + disabledActiveTrackColor: Color(0xFF000004), + disabledInactiveTrackColor: Color(0xFF000005), + disabledSecondaryActiveTrackColor: Color(0xFF000006), + activeTickMarkColor: Color(0xFF000007), + inactiveTickMarkColor: Color(0xFF000008), + disabledActiveTickMarkColor: Color(0xFF000009), + disabledInactiveTickMarkColor: Color(0xFF000010), + thumbColor: Color(0xFF000011), + overlappingShapeStrokeColor: Color(0xFF000012), + disabledThumbColor: Color(0xFF000013), + overlayColor: Color(0xFF000014), + valueIndicatorColor: Color(0xFF000015), overlayShape: RoundSliderOverlayShape(), tickMarkShape: RoundSliderTickMarkShape(), thumbShape: RoundSliderThumbShape(), @@ -68,17 +70,19 @@ void main() { 'trackHeight: 7.0', 'activeTrackColor: Color(0xff000001)', 'inactiveTrackColor: Color(0xff000002)', - 'disabledActiveTrackColor: Color(0xff000003)', - 'disabledInactiveTrackColor: Color(0xff000004)', - 'activeTickMarkColor: Color(0xff000005)', - 'inactiveTickMarkColor: Color(0xff000006)', - 'disabledActiveTickMarkColor: Color(0xff000007)', - 'disabledInactiveTickMarkColor: Color(0xff000008)', - 'thumbColor: Color(0xff000009)', - 'overlappingShapeStrokeColor: Color(0xff000010)', - 'disabledThumbColor: Color(0xff000011)', - 'overlayColor: Color(0xff000012)', - 'valueIndicatorColor: Color(0xff000013)', + 'secondaryActiveTrackColor: Color(0xff000003)', + 'disabledActiveTrackColor: Color(0xff000004)', + 'disabledInactiveTrackColor: Color(0xff000005)', + 'disabledSecondaryActiveTrackColor: Color(0xff000006)', + 'activeTickMarkColor: Color(0xff000007)', + 'inactiveTickMarkColor: Color(0xff000008)', + 'disabledActiveTickMarkColor: Color(0xff000009)', + 'disabledInactiveTickMarkColor: Color(0xff000010)', + 'thumbColor: Color(0xff000011)', + 'overlappingShapeStrokeColor: Color(0xff000012)', + 'disabledThumbColor: Color(0xff000013)', + 'overlayColor: Color(0xff000014)', + 'valueIndicatorColor: Color(0xff000015)', "overlayShape: Instance of 'RoundSliderOverlayShape'", "tickMarkShape: Instance of 'RoundSliderTickMarkShape'", "thumbShape: Instance of 'RoundSliderThumbShape'", @@ -103,16 +107,18 @@ void main() { final SliderThemeData customTheme = sliderTheme.copyWith( activeTrackColor: Colors.purple, inactiveTrackColor: Colors.purple.withAlpha(0x3d), + secondaryActiveTrackColor: Colors.purple.withAlpha(0x8a), ); - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false)); + await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false)); final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; expect( material, paints ..rrect(color: customTheme.disabledActiveTrackColor) - ..rrect(color: customTheme.disabledInactiveTrackColor), + ..rrect(color: customTheme.disabledInactiveTrackColor) + ..rrect(color: customTheme.disabledSecondaryActiveTrackColor), ); }); @@ -125,16 +131,18 @@ void main() { final SliderThemeData customTheme = sliderTheme.copyWith( activeTrackColor: Colors.purple, inactiveTrackColor: Colors.purple.withAlpha(0x3d), + secondaryActiveTrackColor: Colors.purple.withAlpha(0x8a), ); - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, enabled: false)); + await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, secondaryTrackValue: 0.75, enabled: false)); final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; expect( material, paints ..rrect(color: customTheme.disabledActiveTrackColor) - ..rrect(color: customTheme.disabledInactiveTrackColor), + ..rrect(color: customTheme.disabledInactiveTrackColor) + ..rrect(color: customTheme.disabledSecondaryActiveTrackColor), ); }); @@ -148,13 +156,15 @@ void main() { primaryColor: customColor1, primaryColorDark: customColor2, primaryColorLight: customColor3, - valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: customColor4), + valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: customColor4), ); expect(sliderTheme.activeTrackColor, equals(customColor1.withAlpha(0xff))); expect(sliderTheme.inactiveTrackColor, equals(customColor1.withAlpha(0x3d))); + expect(sliderTheme.secondaryActiveTrackColor, equals(customColor1.withAlpha(0x8a))); expect(sliderTheme.disabledActiveTrackColor, equals(customColor2.withAlpha(0x52))); expect(sliderTheme.disabledInactiveTrackColor, equals(customColor2.withAlpha(0x1f))); + expect(sliderTheme.disabledSecondaryActiveTrackColor, equals(customColor2.withAlpha(0x1f))); expect(sliderTheme.activeTickMarkColor, equals(customColor3.withAlpha(0x8a))); expect(sliderTheme.inactiveTickMarkColor, equals(customColor1.withAlpha(0x8a))); expect(sliderTheme.disabledActiveTickMarkColor, equals(customColor3.withAlpha(0x1f))); @@ -176,7 +186,7 @@ void main() { primaryColor: customColor1, primaryColorDark: customColor2, primaryColorLight: customColor3, - valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: customColor4), + valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: customColor4), ); expect(sliderTheme.overlayShape, const RoundSliderOverlayShape()); @@ -195,13 +205,13 @@ void main() { primaryColor: Colors.black, primaryColorDark: Colors.black, primaryColorLight: Colors.black, - valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: Colors.black), + valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: Colors.black), ).copyWith(trackHeight: 2.0); final SliderThemeData sliderThemeWhite = SliderThemeData.fromPrimaryColors( primaryColor: Colors.white, primaryColorDark: Colors.white, primaryColorLight: Colors.white, - valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyText1!.copyWith(color: Colors.white), + valueIndicatorTextStyle: ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: Colors.white), ).copyWith(trackHeight: 6.0); final SliderThemeData lerp = SliderThemeData.lerp(sliderThemeBlack, sliderThemeWhite, 0.5); const Color middleGrey = Color(0xff7f7f7f); @@ -209,8 +219,10 @@ void main() { expect(lerp.trackHeight, equals(4.0)); expect(lerp.activeTrackColor, equals(middleGrey.withAlpha(0xff))); expect(lerp.inactiveTrackColor, equals(middleGrey.withAlpha(0x3d))); + expect(lerp.secondaryActiveTrackColor, equals(middleGrey.withAlpha(0x8a))); expect(lerp.disabledActiveTrackColor, equals(middleGrey.withAlpha(0x52))); expect(lerp.disabledInactiveTrackColor, equals(middleGrey.withAlpha(0x1f))); + expect(lerp.disabledSecondaryActiveTrackColor, equals(middleGrey.withAlpha(0x1f))); expect(lerp.activeTickMarkColor, equals(middleGrey.withAlpha(0x8a))); expect(lerp.inactiveTickMarkColor, equals(middleGrey.withAlpha(0x8a))); expect(lerp.disabledActiveTickMarkColor, equals(middleGrey.withAlpha(0x1f))); @@ -229,7 +241,7 @@ void main() { ); final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500); - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25)); + await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, secondaryTrackValue: 0.5)); final MaterialInkController material = Material.of(tester.element(find.byType(Slider)))!; const Radius radius = Radius.circular(2); @@ -241,10 +253,11 @@ void main() { material, paints ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.activeTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor), + ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.inactiveTrackColor) + ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 400.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.secondaryActiveTrackColor), ); - await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false)); + await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, secondaryTrackValue: 0.5, enabled: false)); await tester.pumpAndSettle(); // wait for disable animation // The disabled slider thumb is the same size as the enabled thumb. @@ -252,7 +265,8 @@ void main() { material, paints ..rrect(rrect: RRect.fromLTRBAndCorners(24.0, 297.0, 212.0, 303.0, topLeft: activatedRadius, bottomLeft: activatedRadius), color: sliderTheme.disabledActiveTrackColor) - ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor), + ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 776.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledInactiveTrackColor) + ..rrect(rrect: RRect.fromLTRBAndCorners(212.0, 298.0, 400.0, 302.0, topRight: radius, bottomRight: radius), color: sliderTheme.disabledSecondaryActiveTrackColor), ); }); @@ -1348,17 +1362,19 @@ class RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight extends R required Animation enableAnimation, required TextDirection textDirection, required Offset thumbCenter, + Offset? secondaryOffset, bool isDiscrete = false, bool isEnabled = false, double additionalActiveTrackHeight = 2.0, }) { - super.paint(context, offset, parentBox: parentBox, sliderTheme: sliderTheme, enableAnimation: enableAnimation, textDirection: textDirection, thumbCenter: thumbCenter, additionalActiveTrackHeight: this.additionalActiveTrackHeight); + super.paint(context, offset, parentBox: parentBox, sliderTheme: sliderTheme, enableAnimation: enableAnimation, textDirection: textDirection, thumbCenter: thumbCenter, secondaryOffset: secondaryOffset, additionalActiveTrackHeight: this.additionalActiveTrackHeight); } } Widget _buildApp( SliderThemeData sliderTheme, { double value = 0.0, + double? secondaryTrackValue, bool enabled = true, int? divisions, }) { @@ -1370,6 +1386,7 @@ Widget _buildApp( data: sliderTheme, child: Slider( value: value, + secondaryTrackValue: secondaryTrackValue, label: '$value', onChanged: onChanged, divisions: divisions, diff --git a/packages/flutter/test/material/snack_bar_theme_test.dart b/packages/flutter/test/material/snack_bar_theme_test.dart index cd82a63d9da9e..240e27b76e2fc 100644 --- a/packages/flutter/test/material/snack_bar_theme_test.dart +++ b/packages/flutter/test/material/snack_bar_theme_test.dart @@ -58,7 +58,7 @@ void main() { 'disabledActionTextColor: Color(0xff00aa00)', 'contentTextStyle: TextStyle(inherit: true, color: Color(0xff123456))', 'elevation: 2.0', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'behavior: SnackBarBehavior.floating', ]); }); @@ -91,7 +91,7 @@ void main() { final Material material = _getSnackBarMaterial(tester); final RenderParagraph content = _getSnackBarTextRenderObject(tester, text); - expect(content.text.style, Typography.material2018().white.subtitle1); + expect(content.text.style, Typography.material2018().white.titleMedium); expect(material.color, const Color(0xFF333333)); expect(material.elevation, 6.0); expect(material.shape, null); diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index 41a42e9a11956..e78b8df28b23c 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -1147,18 +1147,18 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async testWidgets('Stepper with Alternative Label', (WidgetTester tester) async { int index = 0; - late TextStyle bodyText1Style; - late TextStyle bodyText2Style; - late TextStyle captionStyle; + late TextStyle bodyLargeStyle; + late TextStyle bodyMediumStyle; + late TextStyle bodySmallStyle; await tester.pumpWidget( MaterialApp( home: Material( child: StatefulBuilder( builder: (BuildContext context, StateSetter setState) { - bodyText1Style = Theme.of(context).textTheme.bodyText1!; - bodyText2Style = Theme.of(context).textTheme.bodyText2!; - captionStyle = Theme.of(context).textTheme.caption!; + bodyLargeStyle = Theme.of(context).textTheme.bodyText1!; + bodyMediumStyle = Theme.of(context).textTheme.bodyText2!; + bodySmallStyle = Theme.of(context).textTheme.caption!; return Stepper( type: StepperType.horizontal, currentStep: index, @@ -1171,17 +1171,17 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async Step( title: const Text('Title 1'), content: const Text('Content 1'), - label: Text('Label 1', style: Theme.of(context).textTheme.caption), + label: Text('Label 1', style: Theme.of(context).textTheme.bodySmall), ), Step( title: const Text('Title 2'), content: const Text('Content 2'), - label: Text('Label 2', style: Theme.of(context).textTheme.bodyText1), + label: Text('Label 2', style: Theme.of(context).textTheme.bodyLarge), ), Step( title: const Text('Title 3'), content: const Text('Content 3'), - label: Text('Label 3', style: Theme.of(context).textTheme.bodyText2), + label: Text('Label 3', style: Theme.of(context).textTheme.bodyMedium), ), ], ); @@ -1196,8 +1196,8 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async final Text label3TextWidget = tester.widget(find.text('Label 3')); - expect(captionStyle, label1TextWidget.style); - expect(bodyText2Style, label3TextWidget.style); + expect(bodySmallStyle, label1TextWidget.style); + expect(bodyMediumStyle, label3TextWidget.style); late Text selectedLabelTextWidget; late Text nextLabelTextWidget; @@ -1209,10 +1209,10 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async // Check Styles of Selected Label Text Widgets and Another Label Text Widget selectedLabelTextWidget = tester.widget(find.text('Label ${index + 1}')); - expect(captionStyle, selectedLabelTextWidget.style); + expect(bodySmallStyle, selectedLabelTextWidget.style); nextLabelTextWidget = tester.widget(find.text('Label ${index + 2}')); - expect(bodyText1Style, nextLabelTextWidget.style); + expect(bodyLargeStyle, nextLabelTextWidget.style); // Tap to Step2 Label then, `index` become 1 @@ -1222,11 +1222,11 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async // Check Styles of Selected Label Text Widgets and Another Label Text Widget selectedLabelTextWidget = tester.widget(find.text('Label ${index + 1}')); - expect(bodyText1Style, selectedLabelTextWidget.style); + expect(bodyLargeStyle, selectedLabelTextWidget.style); nextLabelTextWidget = tester.widget(find.text('Label ${index + 2}')); - expect(bodyText2Style, nextLabelTextWidget.style); + expect(bodyMediumStyle, nextLabelTextWidget.style); }); } diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 9eac14b038bca..536ad39c053ce 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -1721,6 +1721,63 @@ void main() { await gesture.up(); }); + testWidgets('disabled switch shows tooltip', (WidgetTester tester) async { + const String longPressTooltip = 'long press tooltip'; + const String tapTooltip = 'tap tooltip'; + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + message: longPressTooltip, + child: Switch( + onChanged: null, + value: true, + ), + ), + ), + ) + ); + + // Default tooltip shows up after long pressed. + final Finder tooltip0 = find.byType(Tooltip); + expect(find.text(longPressTooltip), findsNothing); + + await tester.tap(tooltip0); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(longPressTooltip), findsNothing); + + final TestGesture gestureLongPress = await tester.startGesture(tester.getCenter(tooltip0)); + await tester.pump(); + await tester.pump(kLongPressTimeout); + await gestureLongPress.up(); + await tester.pump(); + + expect(find.text(longPressTooltip), findsOneWidget); + + // Tooltip shows up after tapping when set triggerMode to TooltipTriggerMode.tap. + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Tooltip( + triggerMode: TooltipTriggerMode.tap, + message: tapTooltip, + child: Switch( + onChanged: null, + value: true, + ), + ), + ), + ) + ); + + final Finder tooltip1 = find.byType(Tooltip); + expect(find.text(tapTooltip), findsNothing); + + await tester.tap(tooltip1); + await tester.pump(const Duration(milliseconds: 10)); + expect(find.text(tapTooltip), findsOneWidget); + }); + group('with image', () { late ui.Image image; diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 90d7cd4c4b9fd..7f6d614abaa9a 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -1821,7 +1821,7 @@ void main() { // Wait for context menu to be built. await tester.pumpAndSettle(); final RenderBox container = tester.renderObject(find.descendant( - of: find.byType(RasterWidget), + of: find.byType(SnapshotWidget), matching: find.byType(SizedBox), ).first); expect(container.size, Size.zero); @@ -3620,7 +3620,7 @@ void main() { ); final Text helperText = tester.widget(find.text('helper text')); expect(helperText.style!.color, themeData.hintColor); - expect(helperText.style!.fontSize, Typography.englishLike2014.caption!.fontSize); + expect(helperText.style!.fontSize, Typography.englishLike2014.bodySmall!.fontSize); }); testWidgets('TextField with specified helperStyle', (WidgetTester tester) async { @@ -7290,7 +7290,7 @@ void main() { final ThemeData themeData = ThemeData( textTheme: TextTheme( - subtitle1: TextStyle( + titleMedium: TextStyle( color: Colors.blue[500], ), ), @@ -7312,12 +7312,12 @@ void main() { // Empty TextStyle is overridden by theme await tester.pumpWidget(buildFrame(const TextStyle())); EditableText editableText = tester.widget(find.byType(EditableText)); - expect(editableText.style.color, themeData.textTheme.subtitle1!.color); - expect(editableText.style.background, themeData.textTheme.subtitle1!.background); - expect(editableText.style.shadows, themeData.textTheme.subtitle1!.shadows); - expect(editableText.style.decoration, themeData.textTheme.subtitle1!.decoration); - expect(editableText.style.locale, themeData.textTheme.subtitle1!.locale); - expect(editableText.style.wordSpacing, themeData.textTheme.subtitle1!.wordSpacing); + expect(editableText.style.color, themeData.textTheme.titleMedium!.color); + expect(editableText.style.background, themeData.textTheme.titleMedium!.background); + expect(editableText.style.shadows, themeData.textTheme.titleMedium!.shadows); + expect(editableText.style.decoration, themeData.textTheme.titleMedium!.decoration); + expect(editableText.style.locale, themeData.textTheme.titleMedium!.locale); + expect(editableText.style.wordSpacing, themeData.textTheme.titleMedium!.wordSpacing); // Properties set on TextStyle override theme const Color setColor = Colors.red; diff --git a/packages/flutter/test/material/text_theme_test.dart b/packages/flutter/test/material/text_theme_test.dart index 6e0dbaee00c2c..9338686b4c4e6 100644 --- a/packages/flutter/test/material/text_theme_test.dart +++ b/packages/flutter/test/material/text_theme_test.dart @@ -50,9 +50,9 @@ void main() { test('TextTheme merges properly in the presence of null fields.', () { - const TextTheme partialTheme = TextTheme(headline6: TextStyle(color: Color(0xcafefeed))); + const TextTheme partialTheme = TextTheme(titleLarge: TextStyle(color: Color(0xcafefeed))); final TextTheme fullTheme = ThemeData.fallback().textTheme.merge(partialTheme); - expect(fullTheme.headline6!.color, equals(partialTheme.headline6!.color)); + expect(fullTheme.titleLarge!.color, equals(partialTheme.titleLarge!.color)); const TextTheme onlyHeadlineSmallAndTitleLarge = TextTheme( headlineSmall: TextStyle(color: Color(0xcafefeed)), diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index 1abe3cbaa9a5d..71cbb321dc472 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -25,7 +25,7 @@ class MyThemeExtensionA extends ThemeExtension { } @override - MyThemeExtensionA lerp(ThemeExtension? other, double t) { + MyThemeExtensionA lerp(MyThemeExtensionA? other, double t) { if (other is! MyThemeExtensionA) { return this; } @@ -52,7 +52,7 @@ class MyThemeExtensionB extends ThemeExtension { } @override - MyThemeExtensionB lerp(ThemeExtension? other, double t) { + MyThemeExtensionB lerp(MyThemeExtensionB? other, double t) { if (other is! MyThemeExtensionB) { return this; } @@ -94,8 +94,8 @@ void main() { final ThemeData darkTheme = ThemeData(brightness: Brightness.dark); final Typography typography = Typography.material2018(platform: lightTheme.platform); - expect(lightTheme.textTheme.headline6!.color, typography.black.headline6!.color); - expect(darkTheme.textTheme.headline6!.color, typography.white.headline6!.color); + expect(lightTheme.textTheme.titleLarge!.color, typography.black.titleLarge!.color); + expect(darkTheme.textTheme.titleLarge!.color, typography.white.titleLarge!.color); }); test('Default primary text theme contrasts with primary brightness', () { @@ -103,8 +103,8 @@ void main() { final ThemeData darkTheme = ThemeData(primaryColor: Colors.black); final Typography typography = Typography.material2018(platform: lightTheme.platform); - expect(lightTheme.primaryTextTheme.headline6!.color, typography.black.headline6!.color); - expect(darkTheme.primaryTextTheme.headline6!.color, typography.white.headline6!.color); + expect(lightTheme.primaryTextTheme.titleLarge!.color, typography.black.titleLarge!.color); + expect(darkTheme.primaryTextTheme.titleLarge!.color, typography.white.titleLarge!.color); }); test('Default icon theme contrasts with brightness', () { @@ -112,8 +112,8 @@ void main() { final ThemeData darkTheme = ThemeData(brightness: Brightness.dark); final Typography typography = Typography.material2018(platform: lightTheme.platform); - expect(lightTheme.textTheme.headline6!.color, typography.black.headline6!.color); - expect(darkTheme.textTheme.headline6!.color, typography.white.headline6!.color); + expect(lightTheme.textTheme.titleLarge!.color, typography.black.titleLarge!.color); + expect(darkTheme.textTheme.titleLarge!.color, typography.white.titleLarge!.color); }); test('Default primary icon theme contrasts with primary brightness', () { @@ -121,8 +121,8 @@ void main() { final ThemeData darkTheme = ThemeData(primaryColor: Colors.black); final Typography typography = Typography.material2018(platform: lightTheme.platform); - expect(lightTheme.primaryTextTheme.headline6!.color, typography.black.headline6!.color); - expect(darkTheme.primaryTextTheme.headline6!.color, typography.white.headline6!.color); + expect(lightTheme.primaryTextTheme.titleLarge!.color, typography.black.titleLarge!.color); + expect(darkTheme.primaryTextTheme.titleLarge!.color, typography.white.titleLarge!.color); }); test('light, dark and fallback constructors support useMaterial3', () { @@ -159,15 +159,15 @@ void main() { final ThemeData themeData = ThemeData( fontFamily: 'Ahem', textTheme: const TextTheme( - headline6: TextStyle(fontFamily: 'Roboto'), + titleLarge: TextStyle(fontFamily: 'Roboto'), ), ); - expect(themeData.textTheme.bodyText1!.fontFamily, equals('Ahem')); - expect(themeData.primaryTextTheme.headline3!.fontFamily, equals('Ahem')); + expect(themeData.textTheme.bodyLarge!.fontFamily, equals('Ahem')); + expect(themeData.primaryTextTheme.displaySmall!.fontFamily, equals('Ahem')); // Shouldn't override the specified style's family - expect(themeData.textTheme.headline6!.fontFamily, equals('Roboto')); + expect(themeData.textTheme.titleLarge!.fontFamily, equals('Roboto')); }); test('Can estimate brightness - directly', () { @@ -650,7 +650,6 @@ void main() { useMaterial3: false, visualDensity: VisualDensity.standard, // COLOR - backgroundColor: Colors.black, bottomAppBarColor: Colors.black, canvasColor: Colors.black, cardColor: Colors.black, @@ -658,7 +657,6 @@ void main() { dialogBackgroundColor: Colors.black, disabledColor: Colors.black, dividerColor: Colors.black, - errorColor: Colors.black, focusColor: Colors.black, highlightColor: Colors.black, hintColor: Colors.black, @@ -695,6 +693,7 @@ void main() { drawerTheme: const DrawerThemeData(), elevatedButtonTheme: ElevatedButtonThemeData(style: ElevatedButton.styleFrom(backgroundColor: Colors.green)), expansionTileTheme: const ExpansionTileThemeData(backgroundColor: Colors.black), + filledButtonTheme: FilledButtonThemeData(style: FilledButton.styleFrom(foregroundColor: Colors.green)), floatingActionButtonTheme: const FloatingActionButtonThemeData(backgroundColor: Colors.black), iconButtonTheme: IconButtonThemeData(style: IconButton.styleFrom(foregroundColor: Colors.pink)), listTileTheme: const ListTileThemeData(), @@ -724,6 +723,8 @@ void main() { androidOverscrollIndicator: AndroidOverscrollIndicator.glow, toggleableActiveColor: Colors.black, selectedRowColor: Colors.black, + errorColor: Colors.black, + backgroundColor: Colors.black, ); final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors( @@ -761,7 +762,6 @@ void main() { visualDensity: VisualDensity.standard, // COLOR - backgroundColor: Colors.white, bottomAppBarColor: Colors.white, canvasColor: Colors.white, cardColor: Colors.white, @@ -769,7 +769,6 @@ void main() { dialogBackgroundColor: Colors.white, disabledColor: Colors.white, dividerColor: Colors.white, - errorColor: Colors.white, focusColor: Colors.white, highlightColor: Colors.white, hintColor: Colors.white, @@ -808,6 +807,7 @@ void main() { drawerTheme: const DrawerThemeData(), elevatedButtonTheme: const ElevatedButtonThemeData(), expansionTileTheme: const ExpansionTileThemeData(backgroundColor: Colors.black), + filledButtonTheme: const FilledButtonThemeData(), floatingActionButtonTheme: const FloatingActionButtonThemeData(backgroundColor: Colors.white), iconButtonTheme: const IconButtonThemeData(), listTileTheme: const ListTileThemeData(), @@ -838,6 +838,8 @@ void main() { androidOverscrollIndicator: AndroidOverscrollIndicator.stretch, toggleableActiveColor: Colors.white, selectedRowColor: Colors.white, + errorColor: Colors.white, + backgroundColor: Colors.white, ); final ThemeData themeDataCopy = theme.copyWith( @@ -860,7 +862,6 @@ void main() { visualDensity: otherTheme.visualDensity, // COLOR - backgroundColor: otherTheme.backgroundColor, bottomAppBarColor: otherTheme.bottomAppBarColor, canvasColor: otherTheme.canvasColor, cardColor: otherTheme.cardColor, @@ -868,7 +869,6 @@ void main() { dialogBackgroundColor: otherTheme.dialogBackgroundColor, disabledColor: otherTheme.disabledColor, dividerColor: otherTheme.dividerColor, - errorColor: otherTheme.errorColor, focusColor: otherTheme.focusColor, highlightColor: otherTheme.highlightColor, hintColor: otherTheme.hintColor, @@ -907,6 +907,7 @@ void main() { drawerTheme: otherTheme.drawerTheme, elevatedButtonTheme: otherTheme.elevatedButtonTheme, expansionTileTheme: otherTheme.expansionTileTheme, + filledButtonTheme: otherTheme.filledButtonTheme, floatingActionButtonTheme: otherTheme.floatingActionButtonTheme, iconButtonTheme: otherTheme.iconButtonTheme, listTileTheme: otherTheme.listTileTheme, @@ -937,6 +938,8 @@ void main() { androidOverscrollIndicator: otherTheme.androidOverscrollIndicator, toggleableActiveColor: otherTheme.toggleableActiveColor, selectedRowColor: otherTheme.selectedRowColor, + errorColor: otherTheme.errorColor, + backgroundColor: otherTheme.backgroundColor, ); // For the sanity of the reader, make sure these properties are in the same @@ -958,7 +961,6 @@ void main() { expect(themeDataCopy.visualDensity, equals(otherTheme.visualDensity)); // COLOR - expect(themeDataCopy.backgroundColor, equals(otherTheme.backgroundColor)); expect(themeDataCopy.bottomAppBarColor, equals(otherTheme.bottomAppBarColor)); expect(themeDataCopy.canvasColor, equals(otherTheme.canvasColor)); expect(themeDataCopy.cardColor, equals(otherTheme.cardColor)); @@ -966,7 +968,6 @@ void main() { expect(themeDataCopy.dialogBackgroundColor, equals(otherTheme.dialogBackgroundColor)); expect(themeDataCopy.disabledColor, equals(otherTheme.disabledColor)); expect(themeDataCopy.dividerColor, equals(otherTheme.dividerColor)); - expect(themeDataCopy.errorColor, equals(otherTheme.errorColor)); expect(themeDataCopy.focusColor, equals(otherTheme.focusColor)); expect(themeDataCopy.highlightColor, equals(otherTheme.highlightColor)); expect(themeDataCopy.hintColor, equals(otherTheme.hintColor)); @@ -1005,6 +1006,7 @@ void main() { expect(themeDataCopy.drawerTheme, equals(otherTheme.drawerTheme)); expect(themeDataCopy.elevatedButtonTheme, equals(otherTheme.elevatedButtonTheme)); expect(themeDataCopy.expansionTileTheme, equals(otherTheme.expansionTileTheme)); + expect(themeDataCopy.filledButtonTheme, equals(otherTheme.filledButtonTheme)); expect(themeDataCopy.floatingActionButtonTheme, equals(otherTheme.floatingActionButtonTheme)); expect(themeDataCopy.iconButtonTheme, equals(otherTheme.iconButtonTheme)); expect(themeDataCopy.listTileTheme, equals(otherTheme.listTileTheme)); @@ -1040,6 +1042,8 @@ void main() { expect(themeDataCopy.androidOverscrollIndicator, equals(otherTheme.androidOverscrollIndicator)); expect(themeDataCopy.toggleableActiveColor, equals(otherTheme.toggleableActiveColor)); expect(themeDataCopy.selectedRowColor, equals(otherTheme.selectedRowColor)); + expect(themeDataCopy.errorColor, equals(otherTheme.errorColor)); + expect(themeDataCopy.backgroundColor, equals(otherTheme.backgroundColor)); }); testWidgets('ThemeData.toString has less than 200 characters output', (WidgetTester tester) async { @@ -1113,11 +1117,9 @@ void main() { 'unselectedWidgetColor', 'disabledColor', 'secondaryHeaderColor', - 'backgroundColor', 'dialogBackgroundColor', 'indicatorColor', 'hintColor', - 'errorColor', // TYPOGRAPHY & ICONOGRAPHY 'typography', 'textTheme', @@ -1140,6 +1142,7 @@ void main() { 'dividerTheme', 'drawerTheme', 'elevatedButtonTheme', + 'filledButtonTheme', 'floatingActionButtonTheme', 'iconButtonTheme', 'listTileTheme', @@ -1170,6 +1173,8 @@ void main() { 'androidOverscrollIndicator', 'toggleableActiveColor', 'selectedRowColor', + 'errorColor', + 'backgroundColor', }; final DiagnosticPropertiesBuilder properties = DiagnosticPropertiesBuilder(); diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index d80746db75ca9..ed129c83f2da4 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -387,12 +387,12 @@ void main() { final ThemeData fallback = ThemeData.fallback(); final ThemeData customTheme = fallback.copyWith( primaryTextTheme: fallback.primaryTextTheme.copyWith( - bodyText2: fallback.primaryTextTheme.bodyText2!.copyWith( + bodyMedium: fallback.primaryTextTheme.bodyMedium!.copyWith( fontSize: kMagicFontSize, ), ), ); - expect(customTheme.primaryTextTheme.bodyText2!.fontSize, kMagicFontSize); + expect(customTheme.primaryTextTheme.bodyMedium!.fontSize, kMagicFontSize); late double actualFontSize; await tester.pumpWidget(Directionality( @@ -401,10 +401,10 @@ void main() { data: customTheme, child: Builder(builder: (BuildContext context) { final ThemeData theme = Theme.of(context); - actualFontSize = theme.primaryTextTheme.bodyText2!.fontSize!; + actualFontSize = theme.primaryTextTheme.bodyMedium!.fontSize!; return Text( 'A', - style: theme.primaryTextTheme.bodyText2, + style: theme.primaryTextTheme.bodyMedium, ); }), ), diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 021674b6ffa18..a437b72c4d2ac 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -86,10 +86,10 @@ void main() { 'hourMinuteTextStyle: TextStyle()', 'dayPeriodTextStyle: TextStyle()', 'helpTextStyle: TextStyle()', - 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', - 'hourMinuteShape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', - 'dayPeriodShape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)', - 'dayPeriodBorderSide: BorderSide(Color(0xff000000), 1.0, BorderStyle.solid)', + 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', + 'hourMinuteShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', + 'dayPeriodShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', + 'dayPeriodBorderSide: BorderSide', ]); }); @@ -114,40 +114,40 @@ void main() { final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - Typography.material2014().englishLike.headline2! - .merge(Typography.material2014().black.headline2) + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) .copyWith(color: defaultTheme.colorScheme.primary), ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - Typography.material2014().englishLike.headline2! - .merge(Typography.material2014().black.headline2) + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) .copyWith(color: defaultTheme.colorScheme.onSurface), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - Typography.material2014().englishLike.subtitle1! - .merge(Typography.material2014().black.subtitle1) + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.primary), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - Typography.material2014().englishLike.subtitle1! - .merge(Typography.material2014().black.subtitle1) + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6)), ); final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - Typography.material2014().englishLike.overline! - .merge(Typography.material2014().black.overline), + Typography.material2014().englishLike.labelSmall! + .merge(Typography.material2014().black.labelSmall), ); final CustomPaint dialPaint = tester.widget(findDialPaint); @@ -157,8 +157,8 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - Typography.material2014().englishLike.bodyText1! - .merge(Typography.material2014().black.bodyText1) + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onSurface), ); // ignore: avoid_dynamic_calls @@ -166,8 +166,8 @@ void main() { expect( // ignore: avoid_dynamic_calls secondaryLabels.first.painter.text.style, - Typography.material2014().englishLike.bodyText1! - .merge(Typography.material2014().white.bodyText1) + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onPrimary), ); @@ -227,8 +227,8 @@ void main() { expect(hourDecoration.focusedErrorBorder, OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); expect( hourDecoration.hintStyle, - Typography.material2014().englishLike.headline2! - .merge(defaultTheme.textTheme.headline2!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))), + Typography.material2014().englishLike.displayMedium! + .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))), ); }); @@ -254,8 +254,8 @@ void main() { final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - Typography.material2014().englishLike.bodyText2! - .merge(Typography.material2014().black.bodyText2) + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _selectedColor), ); @@ -263,8 +263,8 @@ void main() { final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - Typography.material2014().englishLike.bodyText2! - .merge(Typography.material2014().black.bodyText2) + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _unselectedColor), ); @@ -272,8 +272,8 @@ void main() { final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - Typography.material2014().englishLike.subtitle1! - .merge(Typography.material2014().black.subtitle1) + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) .merge(timePickerTheme.dayPeriodTextStyle) .copyWith(color: _selectedColor), ); @@ -281,8 +281,8 @@ void main() { final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - Typography.material2014().englishLike.subtitle1! - .merge(Typography.material2014().black.subtitle1) + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) .merge(timePickerTheme.dayPeriodTextStyle) .copyWith(color: _unselectedColor), ); @@ -290,8 +290,8 @@ void main() { final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - Typography.material2014().englishLike.bodyText2! - .merge(Typography.material2014().black.bodyText2) + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.helpTextStyle), ); @@ -302,8 +302,8 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - Typography.material2014().englishLike.bodyText1! - .merge(Typography.material2014().black.bodyText1) + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) .copyWith(color: _unselectedColor), ); // ignore: avoid_dynamic_calls @@ -311,8 +311,8 @@ void main() { expect( // ignore: avoid_dynamic_calls secondaryLabels.first.painter.text.style, - Typography.material2014().englishLike.bodyText1! - .merge(Typography.material2014().white.bodyText1) + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) .copyWith(color: _selectedColor), ); diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index 8607da96ecd60..57efacc76f7f6 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -223,15 +223,15 @@ void main() { of: find.widgetWithText(TextButton, 'First child'), matching: find.byType(DefaultTextStyle), )).style; - expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); - expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration); + expect(textStyle.fontFamily, theme.textTheme.bodyMedium!.fontFamily); + expect(textStyle.decoration, theme.textTheme.bodyMedium!.decoration); textStyle = tester.widget(find.descendant( of: find.widgetWithText(TextButton, 'Second child'), matching: find.byType(DefaultTextStyle), )).style; - expect(textStyle.fontFamily, theme.textTheme.bodyText2!.fontFamily); - expect(textStyle.decoration, theme.textTheme.bodyText2!.decoration); + expect(textStyle.fontFamily, theme.textTheme.bodyMedium!.fontFamily); + expect(textStyle.decoration, theme.textTheme.bodyMedium!.decoration); }); testWidgets('Custom text style except color is applied', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart index 92b7bc300bd94..6071c3ffb10ac 100644 --- a/packages/flutter/test/material/typography_test.dart +++ b/packages/flutter/test/material/typography_test.dart @@ -101,6 +101,26 @@ void main() { expect(nonDefaultPropertyNames, ['black', 'white', 'englishLike', 'dense', 'tall']); }); + test('Can lerp between different typographies', () { + final List all = [ + for (final TargetPlatform platform in TargetPlatform.values) Typography.material2014(platform: platform), + for (final TargetPlatform platform in TargetPlatform.values) Typography.material2018(platform: platform), + for (final TargetPlatform platform in TargetPlatform.values) Typography.material2021(platform: platform), + ]; + + for (final Typography fromTypography in all) { + for (final Typography toTypegraphy in all) { + Object? error; + try { + Typography.lerp(fromTypography, toTypegraphy, 0.5); + } catch (e) { + error = e; + } + expect(error, isNull); + } + } + }); + test('englishLike2018 TextTheme matches Material Design spec', () { // Check the default material text theme against the style values // shown https://material.io/design/typography/#type-scale. diff --git a/packages/flutter/test/painting/beveled_rectangle_border_test.dart b/packages/flutter/test/painting/beveled_rectangle_border_test.dart index 14f4dd9c9e1d3..c3d433040c548 100644 --- a/packages/flutter/test/painting/beveled_rectangle_border_test.dart +++ b/packages/flutter/test/painting/beveled_rectangle_border_test.dart @@ -110,8 +110,8 @@ void main() { test('BeveledRectangleBorder with StrokeAlign', () { const BorderRadius borderRadius = BorderRadius.all(Radius.circular(10)); const BeveledRectangleBorder inside = BeveledRectangleBorder(side: BorderSide(width: 10.0), borderRadius: borderRadius); - const BeveledRectangleBorder center = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.center), borderRadius: borderRadius); - const BeveledRectangleBorder outside = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.outside), borderRadius: borderRadius); + const BeveledRectangleBorder center = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignCenter), borderRadius: borderRadius); + const BeveledRectangleBorder outside = BeveledRectangleBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignOutside), borderRadius: borderRadius); expect(inside.dimensions, const EdgeInsets.all(10.0)); expect(center.dimensions, const EdgeInsets.all(5.0)); expect(outside.dimensions, EdgeInsets.zero); diff --git a/packages/flutter/test/painting/border_rtl_test.dart b/packages/flutter/test/painting/border_rtl_test.dart index 18946a7ccafcc..47b4f1da4c8a2 100644 --- a/packages/flutter/test/painting/border_rtl_test.dart +++ b/packages/flutter/test/painting/border_rtl_test.dart @@ -142,8 +142,7 @@ void main() { ' BoxBorder.lerp() was called with two objects of type SillyBorder\n' ' and Border:\n' ' SillyBorder()\n' - ' Border.all(BorderSide(Color(0xff000000), 0.0,\n' - ' BorderStyle.none))\n' + ' Border.all(BorderSide(width: 0.0, style: none))\n' ' However, only Border and BorderDirectional classes are supported\n' ' by this method.\n' ' For a more general interpolation method, consider using\n' diff --git a/packages/flutter/test/painting/border_side_test.dart b/packages/flutter/test/painting/border_side_test.dart index 35f502394cf84..b4c33c17d8fa5 100644 --- a/packages/flutter/test/painting/border_side_test.dart +++ b/packages/flutter/test/painting/border_side_test.dart @@ -119,21 +119,21 @@ void main() { test('BorderSide - toString', () { expect( const BorderSide(color: Color(0xFFAABBCC), width: 1.2345).toString(), - 'BorderSide(Color(0xffaabbcc), 1.2, BorderStyle.solid)', + 'BorderSide(color: Color(0xffaabbcc), width: 1.2)', ); }); test('BorderSide - lerp with strokeAlign', () { - const BorderSide side0 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.center); - const BorderSide side1 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.outside); - expect(BorderSide.lerp(side0, side1, 0), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.center)); - expect(BorderSide.lerp(side0, side1, 0.5), const BorderSide(width: 0.0, strokeAlign: StrokeAlign.center)); - expect(BorderSide.lerp(side0, side1, 1), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.outside)); + const BorderSide side0 = BorderSide(width: 2.0); + const BorderSide side1 = BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignOutside); + expect(BorderSide.lerp(side0, side1, 0), const BorderSide(width: 2.0)); + expect(BorderSide.lerp(side0, side1, 0.5), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter)); + expect(BorderSide.lerp(side0, side1, 1), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignOutside)); const BorderSide side2 = BorderSide(width: 2.0); - const BorderSide side3 = BorderSide(width: 2.0, strokeAlign: StrokeAlign.center); + const BorderSide side3 = BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter); expect(BorderSide.lerp(side2, side3, 0), const BorderSide(width: 2.0)); - expect(BorderSide.lerp(side2, side3, 0.5), const BorderSide(width: 0.0)); - expect(BorderSide.lerp(side2, side3, 1), const BorderSide(width: 2.0, strokeAlign: StrokeAlign.center)); + expect(BorderSide.lerp(side2, side3, 0.5), const BorderSide(width: 2.0, strokeAlign: -0.5)); + expect(BorderSide.lerp(side2, side3, 1), const BorderSide(width: 2.0, strokeAlign: BorderSide.strokeAlignCenter)); }); } diff --git a/packages/flutter/test/painting/border_test.dart b/packages/flutter/test/painting/border_test.dart index fa2fd4758fa7f..2e055154ca684 100644 --- a/packages/flutter/test/painting/border_test.dart +++ b/packages/flutter/test/painting/border_test.dart @@ -202,8 +202,8 @@ void main() { expect( const Border( left: BorderSide(), - top: BorderSide(strokeAlign: StrokeAlign.center), - right: BorderSide(strokeAlign: StrokeAlign.outside), + top: BorderSide(strokeAlign: BorderSide.strokeAlignCenter), + right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside), ).isUniform, false, ); @@ -262,10 +262,10 @@ void main() { try { final TestCanvas canvas = TestCanvas(); // Border.all supports all StrokeAlign values. - // Border() supports StrokeAlign.inside only. + // Border() supports [BorderSide.strokeAlignInside] only. const Border( - left: BorderSide(strokeAlign: StrokeAlign.center), - right: BorderSide(strokeAlign: StrokeAlign.outside), + left: BorderSide(strokeAlign: BorderSide.strokeAlignCenter), + right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside), ).paint(canvas, const Rect.fromLTWH(10.0, 20.0, 30.0, 40.0)); } on FlutterError catch (e) { error = e; @@ -274,7 +274,7 @@ void main() { expect(error.diagnostics.length, 1); expect( error.diagnostics[0].toStringDeep(), - 'A Border can only draw strokeAlign different than\nStrokeAlign.inside on uniform borders.\n', + 'A Border can only draw strokeAlign different than\nBorderSide.strokeAlignInside on uniform borders.\n', ); }); @@ -282,21 +282,21 @@ void main() { final Border insideBorder = Border.all(width: 10); expect(insideBorder.dimensions, const EdgeInsets.all(10)); - final Border centerBorder = Border.all(width: 10, strokeAlign: StrokeAlign.center); + final Border centerBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignCenter); expect(centerBorder.dimensions, const EdgeInsets.all(5)); - final Border outsideBorder = Border.all(width: 10, strokeAlign: StrokeAlign.outside); + final Border outsideBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignOutside); expect(outsideBorder.dimensions, EdgeInsets.zero); const BorderSide insideSide = BorderSide(width: 10); const BorderDirectional insideBorderDirectional = BorderDirectional(top: insideSide, bottom: insideSide, start: insideSide, end: insideSide); expect(insideBorderDirectional.dimensions, const EdgeInsetsDirectional.all(10)); - const BorderSide centerSide = BorderSide(width: 10, strokeAlign: StrokeAlign.center); + const BorderSide centerSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter); const BorderDirectional centerBorderDirectional = BorderDirectional(top: centerSide, bottom: centerSide, start: centerSide, end: centerSide); expect(centerBorderDirectional.dimensions, const EdgeInsetsDirectional.all(5)); - const BorderSide outsideSide = BorderSide(width: 10, strokeAlign: StrokeAlign.outside); + const BorderSide outsideSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside); const BorderDirectional outsideBorderDirectional = BorderDirectional(top: outsideSide, bottom: outsideSide, start: outsideSide, end: outsideSide); expect(outsideBorderDirectional.dimensions, EdgeInsetsDirectional.zero); }); diff --git a/packages/flutter/test/painting/box_painter_test.dart b/packages/flutter/test/painting/box_painter_test.dart index 7271cbc99ccb1..85fec3f677b5e 100644 --- a/packages/flutter/test/painting/box_painter_test.dart +++ b/packages/flutter/test/painting/box_painter_test.dart @@ -54,8 +54,8 @@ void main() { style: BorderStyle.solid, ); - expect(side1.toString(), equals('BorderSide(Color(0xff000000), 1.0, BorderStyle.solid)')); - expect(side2.toString(), equals('BorderSide(Color(0xff00ffff), 2.0, BorderStyle.solid)')); + expect(side1.toString(), equals('BorderSide')); + expect(side2.toString(), equals('BorderSide(color: Color(0xff00ffff), width: 2.0)')); }); test('Border control test', () { @@ -76,9 +76,7 @@ void main() { test('Border toString test', () { expect( Border.all(width: 4.0).toString(), - equals( - 'Border.all(BorderSide(Color(0xff000000), 4.0, BorderStyle.solid))', - ), + equals('Border.all(BorderSide(width: 4.0))'), ); expect( const Border( @@ -87,9 +85,7 @@ void main() { bottom: BorderSide(width: 3.0), left: BorderSide(width: 3.0), ).toString(), - equals( - 'Border.all(BorderSide(Color(0xff000000), 3.0, BorderStyle.solid))', - ), + equals('Border.all(BorderSide(width: 3.0))'), ); }); diff --git a/packages/flutter/test/painting/rounded_rectangle_border_test.dart b/packages/flutter/test/painting/rounded_rectangle_border_test.dart index aa9c6c8880782..94acd9c660c06 100644 --- a/packages/flutter/test/painting/rounded_rectangle_border_test.dart +++ b/packages/flutter/test/painting/rounded_rectangle_border_test.dart @@ -97,28 +97,28 @@ void main() { expect( ShapeBorder.lerp(r, c, 0.1).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(r, c, 0.2).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.9), 0.9).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(c, r, 0.9).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 10.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(c, r, 0.8).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 20.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(r, c, 0.9), ShapeBorder.lerp(r, c, 0.1), 0.1).toString(), - 'RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', + 'RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(10.0), 82.0% of the way to being a CircleBorder)', ); expect(ShapeBorder.lerp(r, c, 0.1), ShapeBorder.lerp(r, c, 0.1)); @@ -135,19 +135,26 @@ void main() { const RoundedRectangleBorder insideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10)); expect(insideRoundedRectangleBorder.dimensions, const EdgeInsets.all(10)); - const RoundedRectangleBorder centerRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.center)); + const RoundedRectangleBorder centerRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter)); expect(centerRoundedRectangleBorder.dimensions, const EdgeInsets.all(5)); - const RoundedRectangleBorder outsideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.outside)); + const RoundedRectangleBorder outsideRoundedRectangleBorder = RoundedRectangleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside)); expect(outsideRoundedRectangleBorder.dimensions, EdgeInsets.zero); const CircleBorder insideCircleBorder = CircleBorder(side: BorderSide(width: 10)); expect(insideCircleBorder.dimensions, const EdgeInsets.all(10)); - const CircleBorder centerCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.center)); + const CircleBorder centerCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter)); expect(centerCircleBorder.dimensions, const EdgeInsets.all(5)); - const CircleBorder outsideCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: StrokeAlign.outside)); + const CircleBorder outsideCircleBorder = CircleBorder(side: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside)); expect(outsideCircleBorder.dimensions, EdgeInsets.zero); }); + + test('RoundedRectangleBorder.lerp with different StrokeAlign', () { + const RoundedRectangleBorder rInside = RoundedRectangleBorder(side: BorderSide(width: 10.0)); + const RoundedRectangleBorder rOutside = RoundedRectangleBorder(side: BorderSide(width: 20.0, strokeAlign: BorderSide.strokeAlignOutside)); + const RoundedRectangleBorder rCenter = RoundedRectangleBorder(side: BorderSide(width: 15.0, strokeAlign: BorderSide.strokeAlignCenter)); + expect(ShapeBorder.lerp(rInside, rOutside, 0.5), rCenter); + }); } diff --git a/packages/flutter/test/painting/shape_border_test.dart b/packages/flutter/test/painting/shape_border_test.dart index 632db92717a79..fbb217b15d98b 100644 --- a/packages/flutter/test/painting/shape_border_test.dart +++ b/packages/flutter/test/painting/shape_border_test.dart @@ -13,49 +13,49 @@ void main() { final Border b2 = Border.all(color: const Color(0xFF0000FF)); expect( (b1 + b2).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff00ff00))) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff)))', ); expect( (b1 + (b2 + b2)).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff00ff00))) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff), width: 2.0))', ); expect( ((b1 + b2) + b2).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff00ff00))) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff), width: 2.0))', ); expect((b1 + b2) + b2, b1 + (b2 + b2)); expect( (b1 + b2).scale(3.0).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff00ff00), width: 3.0)) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff), width: 3.0))', ); expect( (b1 + b2).scale(0.0).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none))', + 'Border.all(BorderSide(color: Color(0xff00ff00), width: 0.0, style: none)) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff), width: 0.0, style: none))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.0).toString(), - 'Border.all(BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff0000ff))) + ' + 'Border.all(BorderSide(color: Color(0xff00ff00)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.25).toString(), - 'Border.all(BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff003fbf))) + ' + 'Border.all(BorderSide(color: Color(0xff00bf3f)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.5).toString(), - 'Border.all(BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff007f7f))) + ' + 'Border.all(BorderSide(color: Color(0xff007f7f)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 1.0).toString(), - 'Border.all(BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'Border.all(BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))', + 'Border.all(BorderSide(color: Color(0xff00ff00))) + ' + 'Border.all(BorderSide(color: Color(0xff0000ff)))', ); expect((b1 + b2).dimensions, const EdgeInsets.all(2.0)); const Rect rect = Rect.fromLTRB(11.0, 15.0, 299.0, 175.0); @@ -78,49 +78,49 @@ void main() { const BorderDirectional b2 = BorderDirectional(top: side2, start: side2, end: side2, bottom: side2); expect( (b1 + b2).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00)), start: BorderSide(color: Color(0xff00ff00)), end: BorderSide(color: Color(0xff00ff00)), bottom: BorderSide(color: Color(0xff00ff00))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff)), start: BorderSide(color: Color(0xff0000ff)), end: BorderSide(color: Color(0xff0000ff)), bottom: BorderSide(color: Color(0xff0000ff)))', ); expect( (b1 + (b2 + b2)).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00)), start: BorderSide(color: Color(0xff00ff00)), end: BorderSide(color: Color(0xff00ff00)), bottom: BorderSide(color: Color(0xff00ff00))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff), width: 2.0), start: BorderSide(color: Color(0xff0000ff), width: 2.0), end: BorderSide(color: Color(0xff0000ff), width: 2.0), bottom: BorderSide(color: Color(0xff0000ff), width: 2.0))', ); expect( ((b1 + b2) + b2).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00)), start: BorderSide(color: Color(0xff00ff00)), end: BorderSide(color: Color(0xff00ff00)), bottom: BorderSide(color: Color(0xff00ff00))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff), width: 2.0), start: BorderSide(color: Color(0xff0000ff), width: 2.0), end: BorderSide(color: Color(0xff0000ff), width: 2.0), bottom: BorderSide(color: Color(0xff0000ff), width: 2.0))', ); expect((b1 + b2) + b2, b1 + (b2 + b2)); expect( (b1 + b2).scale(3.0).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00), width: 3.0), start: BorderSide(color: Color(0xff00ff00), width: 3.0), end: BorderSide(color: Color(0xff00ff00), width: 3.0), bottom: BorderSide(color: Color(0xff00ff00), width: 3.0)) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff), width: 3.0), start: BorderSide(color: Color(0xff0000ff), width: 3.0), end: BorderSide(color: Color(0xff0000ff), width: 3.0), bottom: BorderSide(color: Color(0xff0000ff), width: 3.0))', ); expect( (b1 + b2).scale(0.0).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), start: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), end: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), start: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), end: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00), width: 0.0, style: none), start: BorderSide(color: Color(0xff00ff00), width: 0.0, style: none), end: BorderSide(color: Color(0xff00ff00), width: 0.0, style: none), bottom: BorderSide(color: Color(0xff00ff00), width: 0.0, style: none)) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff), width: 0.0, style: none), start: BorderSide(color: Color(0xff0000ff), width: 0.0, style: none), end: BorderSide(color: Color(0xff0000ff), width: 0.0, style: none), bottom: BorderSide(color: Color(0xff0000ff), width: 0.0, style: none))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.0).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff)), start: BorderSide(color: Color(0xff0000ff)), end: BorderSide(color: Color(0xff0000ff)), bottom: BorderSide(color: Color(0xff0000ff))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00)), start: BorderSide(color: Color(0xff00ff00)), end: BorderSide(color: Color(0xff00ff00)), bottom: BorderSide(color: Color(0xff00ff00)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.25).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff003fbf)), start: BorderSide(color: Color(0xff003fbf)), end: BorderSide(color: Color(0xff003fbf)), bottom: BorderSide(color: Color(0xff003fbf))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff00bf3f)), start: BorderSide(color: Color(0xff00bf3f)), end: BorderSide(color: Color(0xff00bf3f)), bottom: BorderSide(color: Color(0xff00bf3f)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 0.5).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff007f7f)), start: BorderSide(color: Color(0xff007f7f)), end: BorderSide(color: Color(0xff007f7f)), bottom: BorderSide(color: Color(0xff007f7f))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff007f7f)), start: BorderSide(color: Color(0xff007f7f)), end: BorderSide(color: Color(0xff007f7f)), bottom: BorderSide(color: Color(0xff007f7f)))', ); expect( ShapeBorder.lerp(b2 + b1, b1 + b2, 1.0).toString(), - 'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + ' - 'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))', + 'BorderDirectional(top: BorderSide(color: Color(0xff00ff00)), start: BorderSide(color: Color(0xff00ff00)), end: BorderSide(color: Color(0xff00ff00)), bottom: BorderSide(color: Color(0xff00ff00))) + ' + 'BorderDirectional(top: BorderSide(color: Color(0xff0000ff)), start: BorderSide(color: Color(0xff0000ff)), end: BorderSide(color: Color(0xff0000ff)), bottom: BorderSide(color: Color(0xff0000ff)))', ); expect((b1 + b2).dimensions, const EdgeInsetsDirectional.fromSTEB(2.0, 2.0, 2.0, 2.0)); const Rect rect = Rect.fromLTRB(11.0, 15.0, 299.0, 175.0); diff --git a/packages/flutter/test/painting/stadium_border_test.dart b/packages/flutter/test/painting/stadium_border_test.dart index 5b7edb5cc34d7..39028438c5037 100644 --- a/packages/flutter/test/painting/stadium_border_test.dart +++ b/packages/flutter/test/painting/stadium_border_test.dart @@ -48,8 +48,8 @@ void main() { }); test('StadiumBorder with StrokeAlign', () { - const StadiumBorder center = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.center)); - const StadiumBorder outside = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: StrokeAlign.outside)); + const StadiumBorder center = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignCenter)); + const StadiumBorder outside = StadiumBorder(side: BorderSide(width: 10.0, strokeAlign: BorderSide.strokeAlignOutside)); expect(center.dimensions, const EdgeInsets.all(5.0)); expect(outside.dimensions, EdgeInsets.zero); @@ -103,28 +103,28 @@ void main() { expect( ShapeBorder.lerp(stadium, circle, 0.1).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 10.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 10.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(stadium, circle, 0.2).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 20.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 20.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.9), 0.9).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 82.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 82.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(circle, stadium, 0.9).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 10.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 10.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(circle, stadium, 0.8).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 20.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 20.0% of the way to being a CircleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(stadium, circle, 0.9), ShapeBorder.lerp(stadium, circle, 0.1), 0.1).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), 82.0% of the way to being a CircleBorder)', + 'StadiumBorder(BorderSide(width: 0.0, style: none), 82.0% of the way to being a CircleBorder)', ); expect(ShapeBorder.lerp(stadium, circle, 0.1), ShapeBorder.lerp(stadium, circle, 0.1)); @@ -182,33 +182,33 @@ void main() { expect( ShapeBorder.lerp(stadium, rrect, 0.1).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)', ); expect( ShapeBorder.lerp(stadium, rrect, 0.2).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.1), ShapeBorder.lerp(stadium, rrect, 0.9), 0.9).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)', ); expect( ShapeBorder.lerp(rrect, stadium, 0.9).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 10.0% of the way to being a RoundedRectangleBorder)', ); expect( ShapeBorder.lerp(rrect, stadium, 0.8).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 20.0% of the way to being a RoundedRectangleBorder)', ); expect( ShapeBorder.lerp(ShapeBorder.lerp(stadium, rrect, 0.9), ShapeBorder.lerp(stadium, rrect, 0.1), 0.1).toString(), - 'StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), ' + 'StadiumBorder(BorderSide(width: 0.0, style: none), ' 'BorderRadius.zero, 82.0% of the way to being a RoundedRectangleBorder)', ); diff --git a/packages/flutter/test/painting/star_border_test.dart b/packages/flutter/test/painting/star_border_test.dart index fe336f1680adb..d00b0140b9ec3 100644 --- a/packages/flutter/test/painting/star_border_test.dart +++ b/packages/flutter/test/painting/star_border_test.dart @@ -105,9 +105,9 @@ void main() { await testBorder(tester, 'side_1', const StarBorder(side: BorderSide(color: Color(0xffff0000)))); await testBorder(tester, 'side_10', const StarBorder(side: BorderSide(color: Color(0xffff0000), width: 10))); await testBorder(tester, 'side_align_center', - const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.center))); + const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); await testBorder(tester, 'side_align_outside', - const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.outside))); + const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); }); testWidgets('StarBorder.polygon parameters', (WidgetTester tester) async { @@ -127,9 +127,37 @@ void main() { await testBorder( tester, 'poly_side_10', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), width: 10))); await testBorder(tester, 'poly_side_align_center', - const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.center))); + const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); await testBorder(tester, 'poly_side_align_outside', - const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: StrokeAlign.outside))); + const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); + }); + + testWidgets("StarBorder doesn't try to scale an infinite scale matrix", (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 100, + height: 100, + child: Stack( + children: [ + Positioned.fromRelativeRect( + rect: const RelativeRect.fromLTRB(100, 100, 100, 100), + child: Container( + decoration: const ShapeDecoration( + color: Colors.green, + shape: StarBorder(), + ), + ), + ), + ], + ), + ), + ), + ), + ); + expect(tester.takeException(), isNull); }); testWidgets('StarBorder lerped with StarBorder', (WidgetTester tester) async { diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart index 03dab7b3a81f9..6fa01d65f20c1 100644 --- a/packages/flutter/test/rendering/box_test.dart +++ b/packages/flutter/test/rendering/box_test.dart @@ -36,6 +36,18 @@ class MissingSetSizeRenderBox extends RenderBox { void performLayout() { } } +class BadBaselineRenderBox extends RenderBox { + @override + void performLayout() { + size = constraints.biggest; + } + + @override + double? computeDistanceToActualBaseline(TextBaseline baseline) { + throw Exception(); + } +} + void main() { TestRenderingFlutterBinding.ensureInitialized(); @@ -410,16 +422,65 @@ void main() { expect(firstErrorDetails?.toString(), contains('is not normalized')); }); - test('overflow is reported when insufficient size is given', () { - final RenderConstrainedBox child = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: double.maxFinite)); - final RenderConstraintsTransformBox box = RenderConstraintsTransformBox( - alignment: Alignment.center, - textDirection: TextDirection.ltr, - constraintsTransform: (BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity), - child: child, - ); + test('overflow is reported when insufficient size is given and clipBehavior is Clip.none', () { + bool hadErrors = false; + void expectOverflowedErrors() { + absorbOverflowedErrors(); + hadErrors = true; + } - layout(box, constraints: const BoxConstraints(), phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + final TestClipPaintingContext context = TestClipPaintingContext(); + for (final Clip? clip in [null, ...Clip.values]) { + final RenderConstraintsTransformBox box; + switch (clip) { + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + box = RenderConstraintsTransformBox( + alignment: Alignment.center, + textDirection: TextDirection.ltr, + constraintsTransform: (BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity), + clipBehavior: clip!, + child: RenderConstrainedBox( + additionalConstraints: const BoxConstraints.tightFor( + width: double.maxFinite, + height: double.maxFinite, + ), + ), + ); + break; + case null: + box = RenderConstraintsTransformBox( + alignment: Alignment.center, + textDirection: TextDirection.ltr, + constraintsTransform: (BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity), + child: RenderConstrainedBox( + additionalConstraints: const BoxConstraints.tightFor( + width: double.maxFinite, + height: double.maxFinite, + ), + ), + ); + break; + } + layout(box, constraints: const BoxConstraints(), phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + context.paintChild(box, Offset.zero); + // By default, clipBehavior should be Clip.none + expect(context.clipBehavior, equals(clip ?? Clip.none)); + switch (clip) { + case null: + case Clip.none: + expect(hadErrors, isTrue, reason: 'Should have had overflow errors for $clip'); + break; + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + expect(hadErrors, isFalse, reason: 'Should not have had overflow errors for $clip'); + break; + } + hadErrors = false; + } }); test('handles flow layout', () { @@ -642,26 +703,50 @@ void main() { const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); final TestClipPaintingContext context = TestClipPaintingContext(); - // By default, clipBehavior should be Clip.none - final RenderUnconstrainedBox defaultBox = RenderUnconstrainedBox( - alignment: Alignment.center, - textDirection: TextDirection.ltr, - child: box200x200, - ); - layout(defaultBox, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - context.paintChild(defaultBox, Offset.zero); - expect(context.clipBehavior, equals(Clip.none)); - - for (final Clip clip in Clip.values) { - final RenderUnconstrainedBox box = RenderUnconstrainedBox( - alignment: Alignment.center, - textDirection: TextDirection.ltr, - child: box200x200, - clipBehavior: clip, - ); + bool hadErrors = false; + void expectOverflowedErrors() { + absorbOverflowedErrors(); + hadErrors = true; + } + + for (final Clip? clip in [null, ...Clip.values]) { + final RenderUnconstrainedBox box; + switch (clip) { + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + box = RenderUnconstrainedBox( + alignment: Alignment.center, + textDirection: TextDirection.ltr, + child: box200x200, + clipBehavior: clip!, + ); + break; + case null: + box = RenderUnconstrainedBox( + alignment: Alignment.center, + textDirection: TextDirection.ltr, + child: box200x200, + ); + break; + } layout(box, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + switch (clip) { + case null: + case Clip.none: + expect(hadErrors, isTrue, reason: 'Should have had overflow errors for $clip'); + break; + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + expect(hadErrors, isFalse, reason: 'Should not have had overflow errors for $clip'); + break; + } + hadErrors = false; context.paintChild(box, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior should be Clip.none + expect(context.clipBehavior, equals(clip ?? Clip.none), reason: 'for $clip'); } }); @@ -1123,6 +1208,27 @@ void main() { ), ); }); + + test('debugDoingBaseline flag is cleared after exception', () { + final BadBaselineRenderBox badChild = BadBaselineRenderBox(); + final RenderBox badRoot = RenderBaseline( + child: badChild, + baseline: 0.0, + baselineType: TextBaseline.alphabetic, + ); + final List exceptions = []; + layout(badRoot, onErrors: () { + exceptions.addAll(TestRenderingFlutterBinding.instance.takeAllFlutterExceptions()); + }); + expect(exceptions, isNotEmpty); + + final RenderBox goodRoot = RenderBaseline( + child: RenderDecoratedBox(decoration: const BoxDecoration()), + baseline: 0.0, + baselineType: TextBaseline.alphabetic, + ); + layout(goodRoot, onErrors: () { assert(false); }); + }); } class _DummyHitTestTarget implements HitTestTarget { diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index 8008dbecfba2f..dce4da9da9f1b 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -54,40 +54,44 @@ void main() { TestRenderingFlutterBinding.ensureInitialized(); test('RenderEditable respects clipBehavior', () { - const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); - final TestClipPaintingContext context = TestClipPaintingContext(); - + const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 1.0); final String longString = 'a' * 10000; - // By default, clipBehavior should be Clip.none - final RenderEditable defaultEditable = RenderEditable( - text: TextSpan(text: longString), - textDirection: TextDirection.ltr, - startHandleLayerLink: LayerLink(), - endHandleLayerLink: LayerLink(), - offset: ViewportOffset.zero(), - textSelectionDelegate: _FakeEditableTextState(), - selection: const TextSelection(baseOffset: 0, extentOffset: 0), - ); - layout(defaultEditable, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - context.paintChild(defaultEditable, Offset.zero); - expect(context.clipBehavior, equals(Clip.hardEdge)); - - context.clipBehavior = Clip.none; // Reset as Clip.none won't write into clipBehavior. - for (final Clip clip in Clip.values) { - final RenderEditable editable = RenderEditable( - text: TextSpan(text: longString), - textDirection: TextDirection.ltr, - startHandleLayerLink: LayerLink(), - endHandleLayerLink: LayerLink(), - offset: ViewportOffset.zero(), - textSelectionDelegate: _FakeEditableTextState(), - selection: const TextSelection(baseOffset: 0, extentOffset: 0), - clipBehavior: clip, - ); - layout(editable, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + for (final Clip? clip in [null, ...Clip.values]) { + final TestClipPaintingContext context = TestClipPaintingContext(); + final RenderEditable editable; + switch (clip) { + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + editable = RenderEditable( + text: TextSpan(text: longString), + textDirection: TextDirection.ltr, + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + offset: ViewportOffset.zero(), + textSelectionDelegate: _FakeEditableTextState(), + selection: const TextSelection(baseOffset: 0, extentOffset: 0), + clipBehavior: clip!, + ); + break; + case null: + editable = RenderEditable( + text: TextSpan(text: longString), + textDirection: TextDirection.ltr, + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + offset: ViewportOffset.zero(), + textSelectionDelegate: _FakeEditableTextState(), + selection: const TextSelection(baseOffset: 0, extentOffset: 0), + ); + break; + } + layout(editable, constraints: viewport, phase: EnginePhase.composite, onErrors: expectNoFlutterErrors); context.paintChild(editable, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior is Clip.hardEdge. + expect(context.clipBehavior, equals(clip ?? Clip.hardEdge), reason: 'for $clip'); } }); diff --git a/packages/flutter/test/rendering/flex_test.dart b/packages/flutter/test/rendering/flex_test.dart index eb4517fbec0d5..5f385fc15b371 100644 --- a/packages/flutter/test/rendering/flex_test.dart +++ b/packages/flutter/test/rendering/flex_test.dart @@ -60,18 +60,30 @@ void main() { test('Clip behavior is respected', () { const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); final TestClipPaintingContext context = TestClipPaintingContext(); - - // By default, clipBehavior should be Clip.none - final RenderFlex defaultFlex = RenderFlex(direction: Axis.vertical, children: [box200x200]); - layout(defaultFlex, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - context.paintChild(defaultFlex, Offset.zero); - expect(context.clipBehavior, equals(Clip.none)); - - for (final Clip clip in Clip.values) { - final RenderFlex flex = RenderFlex(direction: Axis.vertical, children: [box200x200], clipBehavior: clip); - layout(flex, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + bool hadErrors = false; + + for (final Clip? clip in [null, ...Clip.values]) { + final RenderFlex flex; + switch (clip) { + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + flex = RenderFlex(direction: Axis.vertical, children: [box200x200], clipBehavior: clip!); + break; + case null: + flex = RenderFlex(direction: Axis.vertical, children: [box200x200]); + break; + } + layout(flex, constraints: viewport, phase: EnginePhase.composite, onErrors: () { + absorbOverflowedErrors(); + hadErrors = true; + }); context.paintChild(flex, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior should be Clip.none + expect(context.clipBehavior, equals(clip ?? Clip.none)); + expect(hadErrors, isTrue); + hadErrors = false; } }); diff --git a/packages/flutter/test/rendering/layers_test.dart b/packages/flutter/test/rendering/layers_test.dart index 090a0204ff7b3..f8c4bf58e1586 100644 --- a/packages/flutter/test/rendering/layers_test.dart +++ b/packages/flutter/test/rendering/layers_test.dart @@ -1010,6 +1010,7 @@ void main() { final PhysicalModelLayer physicalModelLayer = PhysicalModelLayer(); final ColorFilterLayer colorFilterLayer = ColorFilterLayer(); final ShaderMaskLayer shaderMaskLayer = ShaderMaskLayer(); + final TextureLayer textureLayer = TextureLayer(rect: Rect.zero, textureId: 1); expect(offsetLayer.supportsRasterization(), true); expect(opacityLayer.supportsRasterization(), true); expect(clipRectLayer.supportsRasterization(), true); @@ -1019,12 +1020,11 @@ void main() { expect(physicalModelLayer.supportsRasterization(), true); expect(colorFilterLayer.supportsRasterization(), true); expect(shaderMaskLayer.supportsRasterization(), true); + expect(textureLayer.supportsRasterization(), true); // Unsupported. - final TextureLayer textureLayer = TextureLayer(rect: Rect.zero, textureId: 1); final PlatformViewLayer platformViewLayer = PlatformViewLayer(rect: Rect.zero, viewId: 1); - expect(textureLayer.supportsRasterization(), false); expect(platformViewLayer.supportsRasterization(), false); }); } diff --git a/packages/flutter/test/rendering/localized_fonts_test.dart b/packages/flutter/test/rendering/localized_fonts_test.dart index bcb029d837cd2..98497769fdc67 100644 --- a/packages/flutter/test/rendering/localized_fonts_test.dart +++ b/packages/flutter/test/rendering/localized_fonts_test.dart @@ -27,7 +27,7 @@ void main() { home: Builder( builder: (BuildContext context) { const String character = '骨'; - final TextStyle style = Theme.of(context).textTheme.headline2!; + final TextStyle style = Theme.of(context).textTheme.displayMedium!; return Scaffold( body: Container( padding: const EdgeInsets.all(48.0), @@ -71,7 +71,7 @@ void main() { home: Builder( builder: (BuildContext context) { const String character = '骨'; - final TextStyle style = Theme.of(context).textTheme.headline2!; + final TextStyle style = Theme.of(context).textTheme.displayMedium!; return Scaffold( body: Container( padding: const EdgeInsets.all(48.0), @@ -122,7 +122,7 @@ void main() { home: Builder( builder: (BuildContext context) { const String character = '骨'; - final TextStyle style = Theme.of(context).textTheme.headline2!; + final TextStyle style = Theme.of(context).textTheme.displayMedium!; return Scaffold( body: Container( padding: const EdgeInsets.all(48.0), diff --git a/packages/flutter/test/rendering/proxy_box_test.dart b/packages/flutter/test/rendering/proxy_box_test.dart index 0f8bd5f1fde08..95ab5166fa35d 100644 --- a/packages/flutter/test/rendering/proxy_box_test.dart +++ b/packages/flutter/test/rendering/proxy_box_test.dart @@ -536,19 +536,24 @@ void main() { test('RenderFittedBox respects clipBehavior', () { const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); - final TestClipPaintingContext context = TestClipPaintingContext(); - - // By default, clipBehavior should be Clip.none - final RenderFittedBox defaultBox = RenderFittedBox(child: box200x200, fit: BoxFit.none); - layout(defaultBox, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - defaultBox.paint(context, Offset.zero); - expect(context.clipBehavior, equals(Clip.none)); - - for (final Clip clip in Clip.values) { - final RenderFittedBox box = RenderFittedBox(child: box200x200, fit: BoxFit.none, clipBehavior: clip); - layout(box, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + for (final Clip? clip in [null, ...Clip.values]) { + final TestClipPaintingContext context = TestClipPaintingContext(); + final RenderFittedBox box; + switch (clip) { + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + box = RenderFittedBox(child: box200x200, fit: BoxFit.none, clipBehavior: clip!); + break; + case null: + box = RenderFittedBox(child: box200x200, fit: BoxFit.none); + break; + } + layout(box, constraints: viewport, phase: EnginePhase.composite, onErrors: expectNoFlutterErrors); box.paint(context, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior should be Clip.none + expect(context.clipBehavior, equals(clip ?? Clip.none)); } }); diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index 2e7005441d92d..380992109de0b 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -382,13 +382,22 @@ class TestPushLayerPaintingContext extends PaintingContext { } } -void expectOverflowedErrors() { - final FlutterErrorDetails errorDetails = TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!; - final bool overflowed = errorDetails.toString().contains('overflowed'); - if (!overflowed) { - FlutterError.reportError(errorDetails); +// Absorbs errors that don't have "overflowed" in their error details. +void absorbOverflowedErrors() { + final Iterable errorDetails = TestRenderingFlutterBinding.instance.takeAllFlutterErrorDetails(); + final Iterable filtered = errorDetails.where((FlutterErrorDetails details) { + return !details.toString().contains('overflowed'); + }); + if (filtered.isNotEmpty) { + filtered.forEach(FlutterError.reportError); } } +// Reports any FlutterErrors. +void expectNoFlutterErrors() { + final Iterable errorDetails = TestRenderingFlutterBinding.instance.takeAllFlutterErrorDetails(); + errorDetails.forEach(FlutterError.reportError); +} + RenderConstrainedBox get box200x200 => RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(height: 200.0, width: 200.0)); diff --git a/packages/flutter/test/rendering/stack_test.dart b/packages/flutter/test/rendering/stack_test.dart index 099d51c53a076..e08609f5679f5 100644 --- a/packages/flutter/test/rendering/stack_test.dart +++ b/packages/flutter/test/rendering/stack_test.dart @@ -63,30 +63,39 @@ void main() { expect(stack.size.height, equals(100.0)); }); - test('Stack respects clipBehavior', () { + test('Stack has correct clipBehavior', () { const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); - final TestClipPaintingContext context = TestClipPaintingContext(); - // By default, clipBehavior should be Clip.none - final RenderStack defaultStack = RenderStack(textDirection: TextDirection.ltr, children: [box200x200]); - layout(defaultStack, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - defaultStack.paint(context, Offset.zero); - expect(context.clipBehavior, equals(Clip.none)); - - for (final Clip clip in Clip.values) { + for (final Clip? clip in [null, ...Clip.values]) { + final TestClipPaintingContext context = TestClipPaintingContext(); final RenderBox child = box200x200; - final RenderStack stack = RenderStack( - textDirection: TextDirection.ltr, - children: [child], - clipBehavior: clip, - ); + final RenderStack stack; + switch(clip){ + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + stack = RenderStack( + textDirection: TextDirection.ltr, + children: [child], + clipBehavior: clip!, + ); + break; + case null: + stack = RenderStack( + textDirection: TextDirection.ltr, + children: [child], + ); + break; + } { // Make sure that the child is positioned so the stack will consider it as overflowed. final StackParentData parentData = child.parentData! as StackParentData; parentData.left = parentData.right = 0; } - layout(stack, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + layout(stack, constraints: viewport, phase: EnginePhase.composite, onErrors: expectNoFlutterErrors); context.paintChild(stack, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior should be Clip.hardEdge + expect(context.clipBehavior, equals(clip ?? Clip.hardEdge), reason: 'for $clip'); } }); diff --git a/packages/flutter/test/rendering/wrap_test.dart b/packages/flutter/test/rendering/wrap_test.dart index 49d5f75335251..ad23af6556f0b 100644 --- a/packages/flutter/test/rendering/wrap_test.dart +++ b/packages/flutter/test/rendering/wrap_test.dart @@ -208,17 +208,23 @@ void main() { const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); final TestClipPaintingContext context = TestClipPaintingContext(); - // By default, clipBehavior should be Clip.none - final RenderWrap defaultWrap = RenderWrap(textDirection: TextDirection.ltr, children: [box200x200]); - layout(defaultWrap, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); - context.paintChild(defaultWrap, Offset.zero); - expect(context.clipBehavior, equals(Clip.none)); - - for (final Clip clip in Clip.values) { - final RenderWrap wrap = RenderWrap(textDirection: TextDirection.ltr, children: [box200x200], clipBehavior: clip); - layout(wrap, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors); + for (final Clip? clip in [null, ...Clip.values]) { + final RenderWrap wrap; + switch(clip){ + case Clip.none: + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + wrap = RenderWrap(textDirection: TextDirection.ltr, children: [box200x200], clipBehavior: clip!); + break; + case null: + wrap = RenderWrap(textDirection: TextDirection.ltr, children: [box200x200]); + break; + } + layout(wrap, constraints: viewport, phase: EnginePhase.composite, onErrors: expectNoFlutterErrors); context.paintChild(wrap, Offset.zero); - expect(context.clipBehavior, equals(clip)); + // By default, clipBehavior should be Clip.none + expect(context.clipBehavior, equals(clip ?? Clip.none)); } }); } diff --git a/packages/flutter/test/widgets/basic_test.dart b/packages/flutter/test/widgets/basic_test.dart index 7f10e00e629df..695aefe44a5bd 100644 --- a/packages/flutter/test/widgets/basic_test.dart +++ b/packages/flutter/test/widgets/basic_test.dart @@ -578,6 +578,55 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); + testWidgets('UnconstrainedBox warns only when clipBehavior is Clip.none', (WidgetTester tester) async { + for (final Clip? clip in [null, ...Clip.values]) { + // Clear any render objects that were there before so that we can see more + // than one error. Otherwise, it just throws the first one and skips the + // rest, since the render objects haven't changed. + await tester.pumpWidget(const SizedBox()); + await tester.pumpWidget( + Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), + child: clip == null + ? const UnconstrainedBox(child: SizedBox(width: 400, height: 400)) + : UnconstrainedBox( + clipBehavior: clip, + child: const SizedBox(width: 400, height: 400), + ), + ), + ), + ); + + final RenderConstraintsTransformBox renderObject = tester.allRenderObjects.whereType().first; + + // Defaults to Clip.none + expect(renderObject.clipBehavior, equals(clip ?? Clip.none), reason: 'for clip = $clip'); + + switch(clip) { + case null: + case Clip.none: + // the UnconstrainedBox overflows. + final dynamic exception = tester.takeException(); + expect(exception, isFlutterError, reason: 'for clip = $clip'); + // ignore: avoid_dynamic_calls + expect(exception.diagnostics.first.level, DiagnosticLevel.summary, reason: 'for clip = $clip'); + expect( + // ignore: avoid_dynamic_calls + exception.diagnostics.first.toString(), + startsWith('A RenderConstraintsTransformBox overflowed'), + reason: 'for clip = $clip', + ); + break; + case Clip.hardEdge: + case Clip.antiAlias: + case Clip.antiAliasWithSaveLayer: + expect(tester.takeException(), isNull, reason: 'for clip = $clip'); + break; + } + } + }); + group('ConstraintsTransformBox', () { test('toString', () { expect( diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index cab5bd6a18d7a..22fe11099b16e 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -519,7 +519,7 @@ void _defineTests() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreRect: true, ignoreTransform: true)); semantics.dispose(); - }); + }, skip: true); // [intended] https://github.com/flutter/flutter/issues/110107 group('diffing', () { testWidgets('complains about duplicate keys', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart b/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart new file mode 100644 index 0000000000000..3fedcdd1cfb56 --- /dev/null +++ b/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart @@ -0,0 +1,439 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +Future sendKeyCombination( + WidgetTester tester, + SingleActivator activator, +) async { + final List modifiers = [ + if (activator.control) LogicalKeyboardKey.control, + if (activator.shift) LogicalKeyboardKey.shift, + if (activator.alt) LogicalKeyboardKey.alt, + if (activator.meta) LogicalKeyboardKey.meta, + ]; + for (final LogicalKeyboardKey modifier in modifiers) { + await tester.sendKeyDownEvent(modifier); + } + await tester.sendKeyDownEvent(activator.trigger); + await tester.sendKeyUpEvent(activator.trigger); + await tester.pump(); + for (final LogicalKeyboardKey modifier in modifiers.reversed) { + await tester.sendKeyUpEvent(modifier); + } +} + +void main() { + Widget buildSpyAboveEditableText({ + required FocusNode editableFocusNode, + required FocusNode spyFocusNode, + }) { + return MaterialApp( + home: Align( + alignment: Alignment.topLeft, + child: SizedBox( + // Softwrap at exactly 20 characters. + width: 201, + height: 200, + child: ActionSpy( + focusNode: spyFocusNode, + child: EditableText( + controller: TextEditingController(text: 'dummy text'), + showSelectionHandles: true, + autofocus: true, + focusNode: editableFocusNode, + style: const TextStyle(fontSize: 10.0), + textScaleFactor: 1, + // Avoid the cursor from taking up width. + cursorWidth: 0, + cursorColor: Colors.blue, + backgroundCursorColor: Colors.grey, + selectionControls: materialTextSelectionControls, + keyboardType: TextInputType.text, + maxLines: null, + textAlign: TextAlign.left, + ), + ), + ), + ), + ); + } + group('macOS does not accept shortcuts if focus under EditableText', () { + final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); + + testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + + testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + + testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + + testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + + testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + + testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + editable.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + expect(state.lastIntent, isNull); + }, variant: macOSOnly); + }); + + group('macOS does accept shortcuts if focus above EditableText', () { + final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); + + testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + + testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + + testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + + testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + + testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, alt: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + + testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + tester.binding.testTextInput.unregister(); + addTearDown((){ + tester.binding.testTextInput.register(); + }); + final FocusNode editable = FocusNode(); + final FocusNode spy = FocusNode(); + await tester.pumpWidget( + buildSpyAboveEditableText( + editableFocusNode: editable, + spyFocusNode: spy, + ), + ); + spy.requestFocus(); + await tester.pump(); + final ActionSpyState state = tester.state(find.byType(ActionSpy)); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowLeft, meta: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + + state.lastIntent = null; + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, meta: true)); + await tester.pump(); + expect(state.lastIntent, isA()); + }, variant: macOSOnly); + }, skip: kIsWeb); // [intended] specific tests target non-web. +} + +class ActionSpy extends StatefulWidget { + const ActionSpy({super.key, required this.focusNode, required this.child}); + final FocusNode focusNode; + final Widget child; + + @override + State createState() => ActionSpyState(); +} + +class ActionSpyState extends State { + Intent? lastIntent; + late final Map> _actions = >{ + ExtendSelectionByCharacterIntent: CallbackAction(onInvoke: _captureIntent), + ExtendSelectionToNextWordBoundaryIntent: CallbackAction(onInvoke: _captureIntent), + ExtendSelectionToLineBreakIntent: CallbackAction(onInvoke: _captureIntent), + ExpandSelectionToLineBreakIntent: CallbackAction(onInvoke: _captureIntent), + ExpandSelectionToDocumentBoundaryIntent: CallbackAction(onInvoke: _captureIntent), + ExtendSelectionVerticallyToAdjacentLineIntent: CallbackAction(onInvoke: _captureIntent), + ExtendSelectionToDocumentBoundaryIntent: CallbackAction(onInvoke: _captureIntent), + ExtendSelectionToNextWordBoundaryOrCaretLocationIntent: CallbackAction(onInvoke: _captureIntent), + }; + + // ignore: use_setters_to_change_properties + void _captureIntent(Intent intent) { + lastIntent = intent; + } + + @override + Widget build(BuildContext context) { + return Actions( + actions: _actions, + child: Focus( + focusNode: widget.focusNode, + child: widget.child, + ), + ); + } +} diff --git a/packages/flutter/test/widgets/dismissible_test.dart b/packages/flutter/test/widgets/dismissible_test.dart index 759a65b39e6ab..c8a68eaf60bc1 100644 --- a/packages/flutter/test/widgets/dismissible_test.dart +++ b/packages/flutter/test/widgets/dismissible_test.dart @@ -1150,4 +1150,32 @@ void main() { expect(reportedDismissUpdatePreviousReached, false); expect(reportedDismissUpdateProgress, 0.0); }); + + testWidgets('Change direction does not lose child state', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/108961 + Widget buildFrame(DismissDirection direction) { + return Directionality( + textDirection: TextDirection.ltr, + child: Dismissible( + dragStartBehavior: DragStartBehavior.down, + direction: direction, + key: const Key('Dismissible'), + resizeDuration: null, + child: const SizedBox( + width: 100.0, + height: 100.0, + child: Text('I Love Flutter!'), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame(DismissDirection.horizontal)); + final RenderBox textRenderObjectBegin = tester.renderObject(find.text('I Love Flutter!')); + + await tester.pumpWidget(buildFrame(DismissDirection.none)); + final RenderBox textRenderObjectEnd = tester.renderObject(find.text('I Love Flutter!')); + + expect(identical(textRenderObjectBegin, textRenderObjectEnd), true); + }); } diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart index 1708f82a86323..b0d374c4f04fc 100644 --- a/packages/flutter/test/widgets/editable_text_cursor_test.dart +++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart @@ -68,7 +68,7 @@ void main() { key: editableTextKey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -123,7 +123,7 @@ void main() { key: editableTextKey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -962,7 +962,7 @@ void main() { key: editableTextKey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018(platform: TargetPlatform.iOS).black.subtitle1!, + style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -1023,7 +1023,7 @@ void main() { key: editableTextKey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018(platform: TargetPlatform.iOS).black.subtitle1!, + style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index c7921fd0d751c..98cbbf0653f0a 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -2506,7 +2506,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -2584,7 +2584,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -2630,7 +2630,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -2667,7 +2667,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, onEditingComplete: () { onEditingCompleteCalled = true; @@ -2707,7 +2707,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, onEditingComplete: () { onEditingCompleteCalled = true; @@ -2747,7 +2747,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, onEditingComplete: () { onEditingCompleteCalled = true; @@ -2786,7 +2786,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, maxLines: 3, onEditingComplete: () { @@ -2822,7 +2822,7 @@ void main() { Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, focusNode: focusNode, controller: controller, @@ -2846,7 +2846,7 @@ void main() { widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, focusNode: focusNode, controller: controller, @@ -2887,7 +2887,7 @@ void main() { final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, focusNode: focusNode, controller: controller, @@ -2963,7 +2963,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: controller, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, autocorrectionTextRectColor: rectColor, showCursor: false, @@ -3031,7 +3031,7 @@ void main() { focusNode: focusNode, style: Typography.material2018() .black - .subtitle1!, + .titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -4374,7 +4374,7 @@ void main() { child: EditableText( controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), @@ -4404,7 +4404,7 @@ void main() { child: EditableText( controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), @@ -4448,7 +4448,7 @@ void main() { key: ValueKey(controller1.text), controller: controller1, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), @@ -4457,7 +4457,7 @@ void main() { key: ValueKey(controller2.text), controller: controller2, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, minLines: 10, @@ -4574,7 +4574,7 @@ void main() { key: ValueKey(controller.text), controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), @@ -4614,7 +4614,7 @@ void main() { key: ValueKey(controller.text), controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, scribbleEnabled: false, @@ -4964,7 +4964,7 @@ void main() { child: EditableText( controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardAppearance: Brightness.dark, @@ -5041,7 +5041,7 @@ void main() { showSelectionHandles: true, controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -5110,7 +5110,7 @@ void main() { showSelectionHandles: true, controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -5285,7 +5285,7 @@ void main() { controller: controller, showSelectionHandles: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -5422,7 +5422,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -6183,7 +6183,7 @@ void main() { controller: controller, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -6363,7 +6363,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -6514,7 +6514,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -6675,7 +6675,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -6837,7 +6837,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7031,7 +7031,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7143,7 +7143,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7208,7 +7208,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7400,7 +7400,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7591,7 +7591,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7693,7 +7693,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7759,7 +7759,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -7844,7 +7844,7 @@ void main() { showSelectionHandles: true, controller: controller, focusNode: FocusNode(), - style: Typography.material2018(platform: TargetPlatform.iOS).black.subtitle1!, + style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: cupertinoTextSelectionControls, @@ -8020,7 +8020,7 @@ void main() { maxLines: 2, controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -8279,7 +8279,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8377,7 +8377,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, inputFormatters: [LengthLimitingTextInputFormatter(6)], onChanged: (String s) => controller.text += ' onChanged', @@ -8477,7 +8477,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, inputFormatters: [LengthLimitingTextInputFormatter(6)], ), @@ -8521,7 +8521,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8570,7 +8570,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8581,7 +8581,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8633,7 +8633,7 @@ void main() { focusNode: focusNode1, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8645,7 +8645,7 @@ void main() { focusNode: focusNode2, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8683,7 +8683,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -8732,7 +8732,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); @@ -9188,7 +9188,7 @@ void main() { home: EditableText( controller: controller, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), @@ -9250,7 +9250,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -9524,7 +9524,7 @@ void main() { backgroundCursorColor: Colors.grey, controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, keyboardType: TextInputType.text, @@ -10090,7 +10090,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, selectionControls: materialTextSelectionControls, onSelectionChanged: (TextSelection selection, SelectionChangedCause? cause) { @@ -10117,7 +10117,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, onChanged: (String text) { throw FlutterError(errorText); @@ -10143,7 +10143,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, onEditingComplete: () { throw FlutterError(errorText); @@ -10174,7 +10174,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, onSubmitted: (String text) { throw FlutterError(errorText); @@ -10210,7 +10210,7 @@ void main() { focusNode: FocusNode(), cursorColor: Colors.red, backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.subtitle1!.copyWith(fontFamily: 'Roboto'), + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ), )); @@ -10289,7 +10289,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -10345,7 +10345,7 @@ void main() { controller: controller, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardType: TextInputType.text, @@ -10484,7 +10484,7 @@ void main() { controller: controller, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardType: TextInputType.text, @@ -10648,7 +10648,7 @@ void main() { controller: controller, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardType: TextInputType.text, @@ -10744,7 +10744,7 @@ void main() { controller: controller, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardType: TextInputType.text, @@ -10982,7 +10982,7 @@ void main() { controller: controller, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, keyboardType: TextInputType.text, @@ -11075,7 +11075,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -11124,7 +11124,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -11165,7 +11165,7 @@ void main() { setState = setter; return EditableText( focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: enableInteractiveSelection ? materialTextSelectionControls : null, @@ -11287,7 +11287,7 @@ void main() { child: EditableText( key: key, focusNode: focusNode, - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, controller: controller, @@ -12200,7 +12200,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12281,7 +12281,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12347,7 +12347,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12427,7 +12427,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12526,7 +12526,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12603,7 +12603,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -12808,7 +12808,7 @@ void main() { showSelectionHandles: true, autofocus: true, focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, selectionControls: materialTextSelectionControls, @@ -13141,7 +13141,7 @@ class _TransformedEditableTextState extends State { child: EditableText( controller: TextEditingController(), focusNode: FocusNode(), - style: Typography.material2018().black.subtitle1!, + style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, ), diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index d0f3cd56f8cc9..ec1bb271f4384 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -52,6 +52,7 @@ class FadeInImageElements { RawImage get rawImage => rawImageElement.widget as RawImage; double get opacity => rawImage.opacity?.value ?? 1.0; BoxFit? get fit => rawImage.fit; + FilterQuality? get filterQuality => rawImage.filterQuality; } class LoadTestImageProvider extends ImageProvider { @@ -517,5 +518,36 @@ Future main() async { expect(findFadeInImage(tester).placeholder!.fit, equals(BoxFit.fill)); }); }); + + group("placeholder's FilterQuality", () { + testWidgets("should be the image's FilterQuality when not set", (WidgetTester tester) async { + final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); + final TestImageProvider imageProvider = TestImageProvider(targetImage); + + await tester.pumpWidget(FadeInImage( + placeholder: placeholderProvider, + image: imageProvider, + filterQuality: FilterQuality.medium, + )); + + expect(findFadeInImage(tester).placeholder!.filterQuality, equals(findFadeInImage(tester).target.filterQuality)); + expect(findFadeInImage(tester).placeholder!.filterQuality, equals(FilterQuality.medium)); + }); + + testWidgets('should be the given value when set', (WidgetTester tester) async { + final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); + final TestImageProvider imageProvider = TestImageProvider(targetImage); + + await tester.pumpWidget(FadeInImage( + placeholder: placeholderProvider, + image: imageProvider, + filterQuality: FilterQuality.medium, + placeholderFilterQuality: FilterQuality.high, + )); + + expect(findFadeInImage(tester).target.filterQuality, equals(FilterQuality.medium)); + expect(findFadeInImage(tester).placeholder!.filterQuality, equals(FilterQuality.high)); + }); + }); }); } diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart index e85c4ce6d12f4..176d2b169dc31 100644 --- a/packages/flutter/test/widgets/heroes_test.dart +++ b/packages/flutter/test/widgets/heroes_test.dart @@ -327,8 +327,7 @@ Future main() async { await tester.pumpWidget( HeroControllerScope( controller: HeroController(), - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: key, initialRoute: 'navigator1', @@ -382,8 +381,7 @@ Future main() async { await tester.pumpWidget( HeroControllerScope( controller: HeroController(), - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: key, initialRoute: 'navigator1', @@ -3160,3 +3158,20 @@ Future main() async { }, ); } + +class TestDependencies extends StatelessWidget { + const TestDependencies({required this.child, super.key}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: child, + ), + ); + } +} diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index 8b48f2a5b6555..47af959a1e7ef 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -35,6 +35,53 @@ void main() { imageCache.maximumSize = originalCacheSize; }); + testWidgets('Verify Image does not use disposed handles', (WidgetTester tester) async { + final ui.Image image100x100 = (await tester.runAsync(() async => createTestImage(width: 100, height: 100)))!; + + final _TestImageProvider imageProvider1 = _TestImageProvider(); + final _TestImageProvider imageProvider2 = _TestImageProvider(); + + final ValueNotifier<_TestImageProvider> imageListenable = ValueNotifier<_TestImageProvider>(imageProvider1); + final ValueNotifier innerListenable = ValueNotifier(0); + + bool imageLoaded = false; + + await tester.pumpWidget(ValueListenableBuilder<_TestImageProvider>( + valueListenable: imageListenable, + builder: (BuildContext context, _TestImageProvider image, Widget? child) => Image( + image: image, + frameBuilder: (BuildContext context, Widget child, int? frame, bool wasSynchronouslyLoaded) { + if (frame == 0) { + imageLoaded = true; + } + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) => ValueListenableBuilder( + valueListenable: innerListenable, + builder: (BuildContext context, int value, Widget? valueListenableChild) => KeyedSubtree( + key: UniqueKey(), + child: child, + ), + ), + ); + }, + ), + )); + + imageLoaded = false; + imageProvider1.complete(image10x10); + await tester.idle(); + await tester.pump(); + expect(imageLoaded, true); + + imageLoaded = false; + imageListenable.value = imageProvider2; + innerListenable.value += 1; + imageProvider2.complete(image100x100); + await tester.idle(); + await tester.pump(); + expect(imageLoaded, true); + }); + testWidgets('Verify Image resets its RenderImage when changing providers', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final _TestImageProvider imageProvider1 = _TestImageProvider(); diff --git a/packages/flutter/test/widgets/inherited_model_test.dart b/packages/flutter/test/widgets/inherited_model_test.dart index ebc15a9241f27..f18deffcc882d 100644 --- a/packages/flutter/test/widgets/inherited_model_test.dart +++ b/packages/flutter/test/widgets/inherited_model_test.dart @@ -226,7 +226,7 @@ void main() { final Widget showABC = Builder( builder: (BuildContext context) { final ABCModel abc = ABCModel.of(context)!; - return Text('a: ${abc.a} b: ${abc.b} c: ${abc.c}', style: Theme.of(context).textTheme.headline6); + return Text('a: ${abc.a} b: ${abc.b} c: ${abc.c}', style: Theme.of(context).textTheme.titleLarge); }, ); @@ -343,7 +343,7 @@ void main() { final Widget showABC = Builder( builder: (BuildContext context) { final ABCModel abc = ABCModel.of(context)!; - return Text('a: ${abc.a} b: ${abc.b} c: ${abc.c}', style: Theme.of(context).textTheme.headline6); + return Text('a: ${abc.a} b: ${abc.b} c: ${abc.c}', style: Theme.of(context).textTheme.titleLarge); }, ); diff --git a/packages/flutter/test/widgets/magnifier_test.dart b/packages/flutter/test/widgets/magnifier_test.dart index 4ae35a637d91a..0f60374b47deb 100644 --- a/packages/flutter/test/widgets/magnifier_test.dart +++ b/packages/flutter/test/widgets/magnifier_test.dart @@ -226,7 +226,7 @@ void main() { final OverlayEntry fakeBeforeOverlayEntry = OverlayEntry(builder: (_) => fakeBefore); - Overlay.of(context)!.insert(fakeBeforeOverlayEntry); + Overlay.of(context).insert(fakeBeforeOverlayEntry); magnifierController.show( context: context, builder: (_) => fakeMagnifier, diff --git a/packages/flutter/test/widgets/navigator_restoration_test.dart b/packages/flutter/test/widgets/navigator_restoration_test.dart index 4711ad8acb0c1..41d8087d4e5ac 100644 --- a/packages/flutter/test/widgets/navigator_restoration_test.dart +++ b/packages/flutter/test/widgets/navigator_restoration_test.dart @@ -1042,9 +1042,12 @@ class PagedTestWidget extends StatelessWidget { Widget build(BuildContext context) { return RootRestorationScope( restorationId: restorationId, - child: const Directionality( + child: Directionality( textDirection: TextDirection.ltr, - child: PagedTestNavigator(), + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: const PagedTestNavigator(), + ), ), ); } @@ -1167,20 +1170,23 @@ class TestWidget extends StatelessWidget { restorationId: restorationId, child: Directionality( textDirection: TextDirection.ltr, - child: Navigator( - initialRoute: 'home', - restorationScopeId: 'app', - onGenerateRoute: (RouteSettings settings) { - return MaterialPageRoute( - settings: settings, - builder: (BuildContext context) { - return RouteWidget( - name: settings.name!, - arguments: settings.arguments, - ); - }, - ); - }, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: Navigator( + initialRoute: 'home', + restorationScopeId: 'app', + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + return RouteWidget( + name: settings.name!, + arguments: settings.arguments, + ); + }, + ); + }, + ), ), ), ); diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 1ea27482660bb..ba157a91aedb3 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; @@ -85,7 +83,7 @@ class OnTapPage extends StatelessWidget { onTap: onTap, behavior: HitTestBehavior.opaque, child: Center( - child: Text(id, style: Theme.of(context).textTheme.headline3), + child: Text(id, style: Theme.of(context).textTheme.displaySmall), ), ), ); @@ -201,8 +199,7 @@ void main() { }; final GlobalKey navigator = GlobalKey(); await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Navigator( key: navigator, pages: pages, @@ -566,8 +563,7 @@ void main() { } final TabController controller = TabController(length: 3, vsync: tester); await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: TabBarView( controller: controller, children: [ @@ -598,8 +594,7 @@ void main() { ); } await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: buildNavigator(), ), ); @@ -608,8 +603,7 @@ void main() { pages.add(const MaterialPage(child: Text('Page 2'))); await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: buildNavigator(), ), ); @@ -641,8 +635,7 @@ void main() { ); } await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: buildNavigator(), ), ); @@ -659,8 +652,7 @@ void main() { ]; await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: buildNavigator(), ), ); @@ -848,7 +840,7 @@ void main() { }); testWidgets('pushReplacement correctly reports didReplace to the observer', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/56892. + // Regression test for https://github.com/flutter/flutter/issues/56892. final Map routes = { '/' : (BuildContext context) => const OnTapPage( id: '/', @@ -1904,8 +1896,7 @@ void main() { testWidgets('initial routes below opaque route are offstage', (WidgetTester tester) async { final GlobalKey testKey = GlobalKey(); await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Navigator( key: testKey, initialRoute: '/a/b', @@ -1947,8 +1938,7 @@ void main() { bool onGenerateInitialRoutesCalled = false; final GlobalKey testKey = GlobalKey(); await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Navigator( key: testKey, initialRoute: 'Hello World', @@ -2074,8 +2064,7 @@ void main() { final Map> routeNameToContext = >{}; await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Navigator( key: navigator, initialRoute: 'root', @@ -2154,8 +2143,7 @@ void main() { Widget widgetUnderTest({required bool enabled}) { return TickerMode( enabled: enabled, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( initialRoute: 'root', onGenerateRoute: (RouteSettings settings) { @@ -2261,8 +2249,7 @@ void main() { await tester.pumpWidget( HeroControllerScope( controller: spy, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: top, initialRoute: 'top1', @@ -2332,8 +2319,7 @@ void main() { await tester.pumpWidget( HeroControllerScope( controller: spy, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: key1, initialRoute: 'navigator1', @@ -2353,8 +2339,7 @@ void main() { await tester.pumpWidget( HeroControllerScope( controller: spy, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: key2, initialRoute: 'navigator2', @@ -2412,8 +2397,7 @@ void main() { ); }; await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Stack( children: [ HeroControllerScope( @@ -2459,8 +2443,7 @@ void main() { // Swaps the spies. await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, + TestDependencies( child: Stack( children: [ HeroControllerScope( @@ -2532,8 +2515,7 @@ void main() { await tester.pumpWidget( HeroControllerScope( controller: spy, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Stack( children: [ Navigator( @@ -2571,8 +2553,7 @@ void main() { await tester.pumpWidget( HeroControllerScope( controller: spy, - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Stack( children: [ Navigator( @@ -2637,8 +2618,7 @@ void main() { DefaultMaterialLocalizations.delegate, DefaultWidgetsLocalizations.delegate, ], - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( key: key, pages: pages, @@ -2736,8 +2716,7 @@ void main() { DefaultMaterialLocalizations.delegate, DefaultWidgetsLocalizations.delegate, ], - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( pages: myPages, ), @@ -2832,8 +2811,7 @@ void main() { DefaultMaterialLocalizations.delegate, DefaultWidgetsLocalizations.delegate, ], - child: Directionality( - textDirection: TextDirection.ltr, + child: TestDependencies( child: Navigator( pages: myPages, ), @@ -3086,8 +3064,7 @@ void main() { testWidgets('Pop no animation page does not crash', (WidgetTester tester) async { // Regression Test for https://github.com/flutter/flutter/issues/86604. Widget buildNavigator(bool secondPage) { - return Directionality( - textDirection: TextDirection.ltr, + return TestDependencies( child: Navigator( pages: >[ const ZeroDurationPage( @@ -3691,8 +3668,7 @@ void main() { testWidgets('Can reuse NavigatorObserver in rebuilt tree', (WidgetTester tester) async { final NavigatorObserver observer = NavigatorObserver(); Widget build([Key? key]) { - return Directionality( - textDirection: TextDirection.ltr, + return TestDependencies( child: Navigator( key: key, observers: [observer], @@ -3869,8 +3845,7 @@ void main() { testWidgets('class implementing NavigatorObserver can be used without problems', (WidgetTester tester) async { final _MockNavigatorObserver observer = _MockNavigatorObserver(); Widget build([Key? key]) { - return Directionality( - textDirection: TextDirection.ltr, + return TestDependencies( child: Navigator( key: key, observers: [observer], @@ -4122,7 +4097,7 @@ class ZeroDurationPage extends Page { class ZeroDurationPageRoute extends PageRoute { ZeroDurationPageRoute({required ZeroDurationPage page}) - : super(settings: page, preferRasterization: false); + : super(settings: page, allowSnapshotting: false); @override Duration get transitionDuration => Duration.zero; @@ -4163,3 +4138,20 @@ class _MockNavigatorObserver implements NavigatorObserver { return null; } } + +class TestDependencies extends StatelessWidget { + const TestDependencies({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: Directionality( + textDirection: TextDirection.ltr, + child: child, + ) + ); + } +} diff --git a/packages/flutter/test/widgets/nested_scroll_view_test.dart b/packages/flutter/test/widgets/nested_scroll_view_test.dart index 4f085c4c41e94..357bee470710d 100644 --- a/packages/flutter/test/widgets/nested_scroll_view_test.dart +++ b/packages/flutter/test/widgets/nested_scroll_view_test.dart @@ -2216,7 +2216,7 @@ void main() { await tester.drag(find.text('Item 49'), const Offset(0.0, -50.0)); await tester.pump(); // If handled correctly, the last item should still be visible and - // progressing back down to the bottom edge, instead of jumping further + // progressing back down to the bottom edge, instead of jumping further // up the list and out of view. expect(find.text('Item 49'), findsOneWidget); await tester.pumpAndSettle(); diff --git a/packages/flutter/test/widgets/overlay_test.dart b/packages/flutter/test/widgets/overlay_test.dart index d150a261fb95b..98c3ba24b191c 100644 --- a/packages/flutter/test/widgets/overlay_test.dart +++ b/packages/flutter/test/widgets/overlay_test.dart @@ -694,7 +694,7 @@ void main() { await tester.pump(); }); - testWidgets('OverlayState.of() called without Overlay being exist', (WidgetTester tester) async { + testWidgets('OverlayState.of() throws when called if an Overlay does not exist', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -712,7 +712,8 @@ void main() { expect(error.diagnostics[2].level, DiagnosticLevel.hint); expect(error.diagnostics[2].toStringDeep(), equalsIgnoringHashCodes( 'The most common way to add an Overlay to an application is to\n' - 'include a MaterialApp or Navigator widget in the runApp() call.\n', + 'include a MaterialApp, CupertinoApp or Navigator widget in the\n' + 'runApp() call.\n' )); expect(error.diagnostics[3], isA>()); expect(error.diagnostics[3].value, debugRequiredFor); @@ -723,12 +724,13 @@ void main() { ' Container widgets require an Overlay widget ancestor for correct\n' ' operation.\n' ' The most common way to add an Overlay to an application is to\n' - ' include a MaterialApp or Navigator widget in the runApp() call.\n' + ' include a MaterialApp, CupertinoApp or Navigator widget in the\n' + ' runApp() call.\n' ' The specific widget that failed to find an overlay was:\n' ' Container\n' ' The context from which that widget was searching for an overlay\n' ' was:\n' - ' Builder\n', + ' Builder\n' )); } return Container(); @@ -738,6 +740,47 @@ void main() { ); }); + testWidgets("OverlayState.maybeOf() works when an Overlay does and doesn't exist", (WidgetTester tester) async { + final GlobalKey overlayKey = GlobalKey(); + OverlayState? foundState; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + key: overlayKey, + initialEntries: [ + OverlayEntry( + builder: (BuildContext context) { + foundState = Overlay.maybeOf(context); + return Container(); + }, + ), + ], + ), + ), + ); + + expect(tester.takeException(), isNull); + expect(foundState, isNotNull); + foundState = null; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Builder( + builder: (BuildContext context) { + foundState = Overlay.maybeOf(context); + return const SizedBox(); + }, + ), + ), + ); + + expect(tester.takeException(), isNull); + expect(foundState, isNull); + }); + testWidgets('OverlayEntry.opaque can be changed when OverlayEntry is not part of an Overlay (yet)', (WidgetTester tester) async { final GlobalKey overlayKey = GlobalKey(); final Key root = UniqueKey(); diff --git a/packages/flutter/test/widgets/raster_widget_test.dart b/packages/flutter/test/widgets/raster_widget_test.dart deleted file mode 100644 index 96bf9977f6569..0000000000000 --- a/packages/flutter/test/widgets/raster_widget_test.dart +++ /dev/null @@ -1,477 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is run as part of a reduced test set in CI on Mac and Windows -// machines. -@Tags(['reduced-test-set']) - -import 'dart:ui' as ui; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('RasterWidget can rasterize child', (WidgetTester tester) async { - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - final Key key = UniqueKey(); - await tester.pumpWidget(RepaintBoundary( - key: key, - child: Center( - child: RasterWidget( - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ), - )); - // Rasterization is not actually complete until a frame has been pumped through - // the engine. - await tester.pumpAndSettle(); - - await expectLater(find.byKey(key), matchesGoldenFile('raster_widget.yellow.png')); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RasterWidget is not a repaint boundary when rasterizing', (WidgetTester tester) async { - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - await tester.pumpWidget(RepaintBoundary( - child: Center( - child: RasterWidget( - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ), - )); - - expect(tester.layers, hasLength(3)); - expect(tester.layers.last, isA()); - - controller.rasterize = false; - await tester.pump(); - - expect(tester.layers, hasLength(3)); - expect(tester.layers.last, isA()); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RasterWidget repaints when RasterWidgetDelegate notifies listeners', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - await tester.pumpWidget(RepaintBoundary( - child: Center( - child: RasterWidget( - delegate: delegate, - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ), - )); - - expect(delegate.count, 1); - delegate.notify(); - await tester.pump(); - - expect(delegate.count, 2); - - // Remove widget and verify removal of listeners. - await tester.pumpWidget(const SizedBox()); - - delegate.notify(); - await tester.pump(); - - expect(delegate.count, 2); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RasterWidget will recreate raster when controller calls clear', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - await tester.pumpWidget(RepaintBoundary( - child: Center( - child: RasterWidget( - delegate: delegate, - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ), - )); - - expect(delegate.lastImage, isNotNull); - final ui.Image lastImage = delegate.lastImage!; - - await tester.pump(); - - // Raster is re-used - expect(lastImage, equals(delegate.lastImage)); - - controller.clear(); - - await tester.pump(); - // Raster is re-created. - expect(delegate.lastImage, isNotNull); - expect(lastImage, isNot(delegate.lastImage)); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RasterWidget can update the delegate', (WidgetTester tester) async { - final TestDelegate delegateA = TestDelegate(); - final TestDelegate delegateB = TestDelegate() - ..shouldRepaintValue = true; - TestDelegate delegate = delegateA; - - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - late void Function(void Function()) setStateFn; - await tester.pumpWidget(StatefulBuilder( - builder: (BuildContext context, void Function(void Function()) setState) { - setStateFn = setState; - return Center( - child: RasterWidget( - delegate: delegate, - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ); - }) - ); - - expect(delegateA.count, 1); - expect(delegateB.count, 0); - setStateFn(() { - delegate = delegateB; - }); - await tester.pump(); - - expect(delegateA.count, 1); - expect(delegateB.count, 1); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RasterWidget can update the ValueNotifier', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controllerA = RasterWidgetController(rasterize: true); - final RasterWidgetController controllerB = RasterWidgetController(); - RasterWidgetController controller = controllerA; - late void Function(void Function()) setStateFn; - await tester.pumpWidget(StatefulBuilder( - builder: (BuildContext context, void Function(void Function()) setState) { - setStateFn = setState; - return Center( - child: RasterWidget( - delegate: delegate, - controller: controller, - child: Container( - width: 100, - height: 100, - color: const Color(0xFFAABB11), - ), - ), - ); - }) - ); - - expect(delegate.count, 1); - expect(tester.layers.last, isA()); - setStateFn(() { - controller = controllerB; - }); - await tester.pump(); - - expect(delegate.count, 1); - expect(tester.layers.last, isA()); - - // changes to old notifier do not impact widget. - controllerA.rasterize = false; - await tester.pump(); - - expect(delegate.count, 1); - expect(tester.layers.last, isA()); - - await tester.pumpWidget(const SizedBox()); - - // changes to notifier do not impact widget after disposal. - controllerB.rasterize = true; - await tester.pump(); - expect(delegate.count, 1); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget correctly attaches and detaches delegate callbacks', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - final RenderRasterWidget rasterWidget = RenderRasterWidget( - delegate: delegate, - controller: controller, - devicePixelRatio: 1.0, - mode: RasterizeMode.enabled, - ); - - expect(delegate.addedListenerCount, 0); - expect(delegate.removedListenerCount, 0); - - final PipelineOwner owner = PipelineOwner(); - rasterWidget.attach(owner); - - expect(delegate.addedListenerCount, 1); - expect(delegate.removedListenerCount, 0); - - rasterWidget.detach(); - - expect(delegate.addedListenerCount, 1); - expect(delegate.removedListenerCount, 1); - - final TestDelegate updatedDelegate = TestDelegate(); - rasterWidget.delegate = updatedDelegate; - - // No listeners added or removed while not attached. - expect(updatedDelegate.addedListenerCount, 0); - expect(updatedDelegate.removedListenerCount, 0); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget correctly attaches and detaches controller callbacks', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final TestController controller = TestController(); - final RenderRasterWidget rasterWidget = RenderRasterWidget( - delegate: delegate, - controller: controller, - devicePixelRatio: 1.0, - mode: RasterizeMode.enabled, - ); - - expect(controller.addedListenerCount, 0); - expect(controller.removedListenerCount, 0); - - final PipelineOwner owner = PipelineOwner(); - rasterWidget.attach(owner); - - expect(controller.addedListenerCount, 1); - expect(controller.removedListenerCount, 0); - - rasterWidget.detach(); - - expect(controller.addedListenerCount, 1); - expect(controller.removedListenerCount, 1); - - final TestController updatedController = TestController(); - rasterWidget.controller = updatedController; - - // No listeners added or removed while not attached. - expect(updatedController.addedListenerCount, 0); - expect(updatedController.removedListenerCount, 0); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget does not error on rasterization of child with empty size', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - - await tester.pumpWidget( - Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: RasterWidget( - delegate: delegate, - controller: controller, - child: const SizedBox(), - ), - ), - ), - ); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - - testWidgets('RenderRasterWidget throws assertion if platform view is encountered', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - - await tester.pumpWidget( - Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: RasterWidget( - delegate: delegate, - controller: controller, - child: const SizedBox( - width: 100, - height: 100, - child: TestPlatformView(), - ), - ), - ), - ), - ); - - expect(tester.takeException(), isA() - .having((FlutterError error) => error.message, 'message', contains('RasterWidget used with a child that contains a PlatformView'))); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget does not assert if RasterizeMode.forced', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - - await tester.pumpWidget( - Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: RasterWidget( - delegate: delegate, - controller: controller, - mode: RasterizeMode.forced, - child: const SizedBox( - width: 100, - height: 100, - child: TestPlatformView(), - ), - ), - ), - ), - ); - - expect(tester.takeException(), isNull); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget fallbacks to delegate if PlatformView is present', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - final TestFallback fallback = TestFallback(); - await tester.pumpWidget( - Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: RasterWidget( - delegate: delegate, - controller: controller, - fallback: fallback, - child: const SizedBox( - width: 100, - height: 100, - child: TestPlatformView(), - ), - ), - ), - ), - ); - - expect(fallback.calledFallback, 1); - expect(delegate.count, 0); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('RenderRasterWidget fallbacks to delegate if mode: RasterizeMode.fallback', (WidgetTester tester) async { - final TestDelegate delegate = TestDelegate(); - final RasterWidgetController controller = RasterWidgetController(rasterize: true); - final TestFallback fallback = TestFallback(); - await tester.pumpWidget( - Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: RasterWidget( - delegate: delegate, - controller: controller, - fallback: fallback, - mode: RasterizeMode.fallback, - child: const SizedBox( - width: 100, - height: 100, - ), - ), - ), - ), - ); - - expect(fallback.calledFallback, 1); - expect(delegate.count, 0); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 -} - -class TestFallback extends RasterWidgetFallbackDelegate { - int calledFallback = 0; - - @override - void paintFallback(PaintingContext context, ui.Offset offset, ui.Size size, PaintingContextCallback painter) { - calledFallback += 1; - } - -} - -class TestController extends RasterWidgetController { - int addedListenerCount = 0; - int removedListenerCount = 0; - - @override - void addListener(ui.VoidCallback listener) { - addedListenerCount += 1; - super.addListener(listener); - } - - @override - void removeListener(ui.VoidCallback listener) { - removedListenerCount += 1; - super.removeListener(listener); - } -} - -class TestDelegate extends RasterWidgetDelegate { - int count = 0; - bool shouldRepaintValue = false; - ui.Image? lastImage; - - int addedListenerCount = 0; - int removedListenerCount = 0; - - @override - void addListener(ui.VoidCallback listener) { - addedListenerCount += 1; - super.addListener(listener); - } - - @override - void removeListener(ui.VoidCallback listener) { - removedListenerCount += 1; - super.removeListener(listener); - } - - void notify() { - notifyListeners(); - } - - @override - void paint(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { - count += 1; - lastImage = image; - } - - @override - bool shouldRepaint(covariant RasterWidgetDelegate oldDelegate) => shouldRepaintValue; -} - - -class TestPlatformView extends SingleChildRenderObjectWidget { - const TestPlatformView({super.key}); - - @override - RenderObject createRenderObject(BuildContext context) { - return RenderTestPlatformView(); - } -} - -class RenderTestPlatformView extends RenderProxyBox { - - @override - void paint(PaintingContext context, ui.Offset offset) { - context.addLayer(PlatformViewLayer(rect: offset & size, viewId: 1)); - } -} diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index a1cb44bba1f25..4eb8545160d6e 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -22,7 +22,7 @@ class OnTapPage extends StatelessWidget { onTap: onTap, behavior: HitTestBehavior.opaque, child: Center( - child: Text(id, style: Theme.of(context).textTheme.headline3), + child: Text(id, style: Theme.of(context).textTheme.displaySmall), ), ), ); diff --git a/packages/flutter/test/widgets/scroll_activity_test.dart b/packages/flutter/test/widgets/scroll_activity_test.dart index f6dd3235d0f9e..673e4af274b81 100644 --- a/packages/flutter/test/widgets/scroll_activity_test.dart +++ b/packages/flutter/test/widgets/scroll_activity_test.dart @@ -129,6 +129,64 @@ void main() { expect(find.text('Page 9'), findsOneWidget); }); + List childrenSizeIncrease(int n) { + return List.generate(n, (int i) { + return SizedBox(height: 40.0 + i * 3, child: Text('$i')); + }); + } + + testWidgets('Check for duplicate pixels with ClampingScrollPhysics', (WidgetTester tester) async { + final List scrollSimulationXList = []; + final TestScrollPhysics testScrollPhysics = TestScrollPhysics( + scrollSimulationXList, + parent: const ClampingScrollPhysics(), + ); + await tester.pumpWidget( + MaterialApp( + home: ListView( + physics: testScrollPhysics, + children: childrenSizeIncrease(100), + ), + ), + ); + await tester.fling(find.byType(ListView), const Offset(0.0, -4000.0), 4000.0); + await tester.pumpAndSettle(); + final Set checkSet = {}; + checkSet.addAll(scrollSimulationXList); + /// checkSet.length + 1 is because: + /// simulation.x(0.0) will be called in _startSimulation. + /// The first frame of the animation will also call simulation.x(0.0). + /// It can be tolerated that it has at most one duplicate value. + final bool hasOnlyOneDuplicate = scrollSimulationXList.length == checkSet.length + 1; + expect(true, hasOnlyOneDuplicate); // and ends up at the end + }); + + testWidgets('Check for duplicate pixels with BouncingScrollPhysics', (WidgetTester tester) async { + final List scrollSimulationXList = []; + final TestScrollPhysics testScrollPhysics = TestScrollPhysics( + scrollSimulationXList, + parent: const BouncingScrollPhysics(), + ); + await tester.pumpWidget( + MaterialApp( + home: ListView( + physics: testScrollPhysics, + children: childrenSizeIncrease(100), + ), + ), + ); + await tester.fling(find.byType(ListView), const Offset(0.0, -4000.0), 4000.0); + await tester.pumpAndSettle(); + final Set checkSet = {}; + checkSet.addAll(scrollSimulationXList); + /// checkSet.length + 1 is because: + /// simulation.x(0.0) will be call in _startSimulation. + /// The first frame of the animation will also call simulation.x(0.0). + /// It can be tolerated that it has at most one duplicate value. + final bool noDuplicate = scrollSimulationXList.length == checkSet.length + 1; + expect(true, noDuplicate); // and ends up at the end + }); + testWidgets('Pointer is not ignored during trackpad scrolling.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); int? lastTapped; @@ -210,6 +268,62 @@ void main() { }); } +class TestScrollPhysics extends ScrollPhysics { + const TestScrollPhysics(this.scrollSimulationXList, { super.parent }); + + final List scrollSimulationXList; + + @override + Simulation? createBallisticSimulation( + ScrollMetrics position, + double velocity, + ) { + final Simulation? scrollSimulation = super.createBallisticSimulation( + position, + velocity, + ); + if (scrollSimulation != null && scrollSimulationXList != null) { + return TestScrollScrollSimulation( + scrollSimulation, + scrollSimulationXList, + ); + } + return scrollSimulation; + } + + @override + TestScrollPhysics applyTo(ScrollPhysics? ancestor) { + return TestScrollPhysics( + scrollSimulationXList, + parent: buildParent(ancestor), + ); + } +} + +class TestScrollScrollSimulation extends Simulation { + TestScrollScrollSimulation(this.innerScrollSimulation, + this.scrollSimulationXList,); + + final Simulation innerScrollSimulation; + + final List scrollSimulationXList; + + @override + double dx(double time) => innerScrollSimulation.dx(time); + + @override + bool isDone(double time) => innerScrollSimulation.isDone(time); + + @override + double x(double time) { + final double simulationX = innerScrollSimulation.x(time); + if (scrollSimulationXList != null) { + scrollSimulationXList.add(simulationX); + } + return simulationX; + } +} + class PageView62209 extends StatefulWidget { const PageView62209({super.key}); diff --git a/packages/flutter/test/widgets/scroll_position_test.dart b/packages/flutter/test/widgets/scroll_position_test.dart index 5d99899e31dd7..0e1e11bfe2bac 100644 --- a/packages/flutter/test/widgets/scroll_position_test.dart +++ b/packages/flutter/test/widgets/scroll_position_test.dart @@ -33,24 +33,27 @@ Future performTest(WidgetTester tester, bool maintainState) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, - child: Navigator( - key: navigatorKey, - onGenerateRoute: (RouteSettings settings) { - if (settings.name == '/') { - return MaterialPageRoute( - settings: settings, - builder: (_) => const ThePositiveNumbers(from: 0), - maintainState: maintainState, - ); - } else if (settings.name == '/second') { - return MaterialPageRoute( - settings: settings, - builder: (_) => const ThePositiveNumbers(from: 10000), - maintainState: maintainState, - ); - } - return null; - }, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window), + child: Navigator( + key: navigatorKey, + onGenerateRoute: (RouteSettings settings) { + if (settings.name == '/') { + return MaterialPageRoute( + settings: settings, + builder: (_) => const ThePositiveNumbers(from: 0), + maintainState: maintainState, + ); + } else if (settings.name == '/second') { + return MaterialPageRoute( + settings: settings, + builder: (_) => const ThePositiveNumbers(from: 10000), + maintainState: maintainState, + ); + } + return null; + }, + ), ), ), ); diff --git a/packages/flutter/test/widgets/scroll_simulation_test.dart b/packages/flutter/test/widgets/scroll_simulation_test.dart index 69958f91e31ec..99738be6e84ae 100644 --- a/packages/flutter/test/widgets/scroll_simulation_test.dart +++ b/packages/flutter/test/widgets/scroll_simulation_test.dart @@ -23,4 +23,21 @@ void main() { checkInitialConditions(75.0, 614.2093); checkInitialConditions(5469.0, 182.114534); }); + + test('ClampingScrollSimulation velocity eventually reaches zero', () { + void checkFinalConditions(double position, double velocity) { + final ClampingScrollSimulation simulation = ClampingScrollSimulation(position: position, velocity: velocity); + expect(simulation.dx(10.0), equals(0.0)); + } + + checkFinalConditions(51.0, 2000.0); + checkFinalConditions(584.0, 2617.294734); + checkFinalConditions(345.0, 1982.785934); + checkFinalConditions(0.0, 1831.366634); + checkFinalConditions(-156.2, 1541.57665); + checkFinalConditions(4.0, 1139.250439); + checkFinalConditions(4534.0, 1073.553798); + checkFinalConditions(75.0, 614.2093); + checkFinalConditions(5469.0, 182.114534); + }); } diff --git a/packages/flutter/test/widgets/scrollable_fling_test.dart b/packages/flutter/test/widgets/scrollable_fling_test.dart index 1d34b11fe0ba2..bb20ccad067d2 100644 --- a/packages/flutter/test/widgets/scrollable_fling_test.dart +++ b/packages/flutter/test/widgets/scrollable_fling_test.dart @@ -48,7 +48,7 @@ void main() { // Before changing these values, ensure the fling results in a distance that // makes sense. See issue for more context. expect(androidResult, greaterThan(394.0)); - expect(androidResult, lessThan(395.0)); + expect(androidResult, lessThan(408.2)); await pumpTest(tester, TargetPlatform.linux); await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0); @@ -152,6 +152,6 @@ void main() { expect(log, equals(['tap 21'])); await tester.tap(find.byType(Scrollable)); await tester.pump(const Duration(milliseconds: 50)); - expect(log, equals(['tap 21', 'tap 48'])); + expect(log, equals(['tap 21', 'tap 49'])); }); } diff --git a/packages/flutter/test/widgets/scrollable_semantics_test.dart b/packages/flutter/test/widgets/scrollable_semantics_test.dart index 1c8f7ea44dde2..5307fc7a6d73e 100644 --- a/packages/flutter/test/widgets/scrollable_semantics_test.dart +++ b/packages/flutter/test/widgets/scrollable_semantics_test.dart @@ -231,7 +231,7 @@ void main() { expect(semantics, includesNodeWith( scrollExtentMin: 0.0, - scrollPosition: 380.2, + scrollPosition: 394.3, scrollExtentMax: 520.0, actions: [ SemanticsAction.scrollUp, @@ -280,7 +280,7 @@ void main() { expect(semantics, includesNodeWith( scrollExtentMin: 0.0, - scrollPosition: 380.2, + scrollPosition: 394.3, scrollExtentMax: double.infinity, actions: [ SemanticsAction.scrollUp, @@ -292,7 +292,7 @@ void main() { expect(semantics, includesNodeWith( scrollExtentMin: 0.0, - scrollPosition: 760.4, + scrollPosition: 788.6, scrollExtentMax: double.infinity, actions: [ SemanticsAction.scrollUp, diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart index 6cdea4f8817b1..1a276518c936f 100644 --- a/packages/flutter/test/widgets/scrollable_test.dart +++ b/packages/flutter/test/widgets/scrollable_test.dart @@ -946,8 +946,8 @@ void main() { expect(find.byKey(const ValueKey('Box 0')), findsNothing); expect(find.byKey(const ValueKey('Box 52')), findsOneWidget); - expect(expensiveWidgets, 38); - expect(cheapWidgets, 20); + expect(expensiveWidgets, 40); + expect(cheapWidgets, 21); }); testWidgets('Can recommendDeferredLoadingForContext - override heuristic', (WidgetTester tester) async { @@ -989,9 +989,9 @@ void main() { expect(find.byKey(const ValueKey('Box 0')), findsNothing); expect(find.byKey(const ValueKey('Cheap box 52')), findsOneWidget); - expect(expensiveWidgets, 18); - expect(cheapWidgets, 40); - expect(physics.count, 40 + 18); + expect(expensiveWidgets, 17); + expect(cheapWidgets, 44); + expect(physics.count, 44 + 17); }); testWidgets('Can recommendDeferredLoadingForContext - override heuristic and always return true', (WidgetTester tester) async { @@ -1032,7 +1032,7 @@ void main() { expect(find.byKey(const ValueKey('Cheap box 52')), findsOneWidget); expect(expensiveWidgets, 0); - expect(cheapWidgets, 58); + expect(cheapWidgets, 61); }); testWidgets('ensureVisible does not move PageViews', (WidgetTester tester) async { @@ -1439,9 +1439,9 @@ void main() { await tester.sendEventToBinding(testPointer.hover(tester.getCenter(find.byType(Scrollable)))); await tester.sendEventToBinding(testPointer.scrollInertiaCancel()); // Cancel partway through. await tester.pump(); - expect(getScrollOffset(tester), closeTo(333.2944, 0.0001)); + expect(getScrollOffset(tester), closeTo(342.5439, 0.0001)); await tester.pump(const Duration(milliseconds: 4800)); - expect(getScrollOffset(tester), closeTo(333.2944, 0.0001)); + expect(getScrollOffset(tester), closeTo(342.5439, 0.0001)); }); } diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 1e404412edc35..e534f9d353a45 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -1208,6 +1208,43 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), ); + + testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + SelectedContent? content; + + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent, + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Center( + child: Text('How are you'), + ), + ), + ), + ); + final RenderParagraph paragraph = tester.renderObject(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 4), kind: PointerDeviceKind.mouse); + expect(content, isNull); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(textOffsetToPosition(paragraph, 7)); + await gesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'are'); + + // Backwards selection. + await gesture.down(textOffsetToPosition(paragraph, 3)); + expect(content, isNull); + await gesture.moveTo(textOffsetToPosition(paragraph, 0)); + await gesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'How'); + }); } class SelectionSpy extends LeafRenderObjectWidget { diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index 7488a2991c2e8..f9ca40bc2e62f 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -632,7 +632,7 @@ void main() { expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); semantics.dispose(); - }); + }, skip: true); // [intended] https://github.com/flutter/flutter/issues/110107 testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart index 5306450e898ad..7ce68427447e8 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart @@ -151,7 +151,7 @@ void main() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreId: true, ignoreRect: true)); - await tester.fling(find.text('Tile 2'), const Offset(0, -600), 2000); + await tester.fling(find.text('Tile 2'), const Offset(0, -600), 1950); await tester.pumpAndSettle(); expectedSemantics = TestSemantics.root( diff --git a/packages/flutter/test/widgets/snapshot_widget_test.dart b/packages/flutter/test/widgets/snapshot_widget_test.dart new file mode 100644 index 0000000000000..b3f99e75d3481 --- /dev/null +++ b/packages/flutter/test/widgets/snapshot_widget_test.dart @@ -0,0 +1,360 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is run as part of a reduced test set in CI on Mac and Windows +// machines. +@Tags(['reduced-test-set']) + +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('SnapshotWidget can rasterize child', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + final Key key = UniqueKey(); + await tester.pumpWidget(RepaintBoundary( + key: key, + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + child: Container( + width: 100, + height: 100, + color: const Color(0xFFAABB11), + ), + ), + ), + )); + await expectLater(find.byKey(key), matchesGoldenFile('raster_widget.yellow.png')); + + // Now change the color and assert the old snapshot still matches. + await tester.pumpWidget(RepaintBoundary( + key: key, + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + child: Container( + width: 100, + height: 100, + color: const Color(0xFFAA0000), + ), + ), + ), + )); + await expectLater(find.byKey(key), matchesGoldenFile('raster_widget.yellow.png')); + + // Now invoke clear and the raster is re-generated. + controller.clear(); + await tester.pump(); + + await expectLater(find.byKey(key), matchesGoldenFile('raster_widget.red.png')); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('Changing devicePixelRatio does not repaint if snapshotting is not enabled', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(); + final TestPainter painter = TestPainter(); + double devicePixelRatio = 1.0; + late StateSetter localSetState; + + await tester.pumpWidget( + StatefulBuilder(builder: (BuildContext context, StateSetter setState) { + localSetState = setState; + return Center( + child: TestDependencies( + devicePixelRatio: devicePixelRatio, + child: SnapshotWidget( + controller: controller, + painter: painter, + child: const SizedBox(width: 100, height: 100), + ), + ), + ); + }), + ); + + expect(painter.count, 1); + + localSetState(() { + devicePixelRatio = 2.0; + }); + await tester.pump(); + + // Not repainted as dpr was not used. + expect(painter.count, 1); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('Changing devicePixelRatio forces raster regeneration', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + final TestPainter painter = TestPainter(); + double devicePixelRatio = 1.0; + late StateSetter localSetState; + + await tester.pumpWidget( + StatefulBuilder(builder: (BuildContext context, StateSetter setState) { + localSetState = setState; + return Center( + child: TestDependencies( + devicePixelRatio: devicePixelRatio, + child: SnapshotWidget( + controller: controller, + painter: painter, + child: const SizedBox(width: 100, height: 100), + ), + ), + ); + }), + ); + final ui.Image? raster = painter.lastImage; + + expect(raster, isNotNull); + expect(painter.count, 1); + + localSetState(() { + devicePixelRatio = 2.0; + }); + await tester.pump(); + + final ui.Image? newRaster = painter.lastImage; + + expect(painter.count, 2); + expect(raster, isNot(newRaster)); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('SnapshotWidget paints its child as a single picture layer', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget(RepaintBoundary( + child: Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + child: Container( + width: 100, + height: 100, + color: const Color(0xFFAABB11), + ), + ), + ), + ), + )); + + expect(tester.layers, hasLength(3)); + expect(tester.layers.last, isA()); + + controller.allowSnapshotting = false; + await tester.pump(); + + expect(tester.layers, hasLength(3)); + expect(tester.layers.last, isA()); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('SnapshotWidget can update the painter type', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + painter: TestPainter(), + child: const SizedBox(), + ), + ), + ), + ); + + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + painter: TestPainter2(), + child: const SizedBox(), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('RenderSnapshotWidget does not error on rasterization of child with empty size', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + child: const SizedBox(), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + + testWidgets('RenderSnapshotWidget throws assertion if platform view is encountered', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + child: const SizedBox( + width: 100, + height: 100, + child: TestPlatformView(), + ), + ), + ), + ), + ); + + expect(tester.takeException(), isA() + .having((FlutterError error) => error.message, 'message', contains('SnapshotWidget used with a child that contains a PlatformView'))); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('RenderSnapshotWidget does not assert if SnapshotMode.forced', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + mode: SnapshotMode.forced, + child: const SizedBox( + width: 100, + height: 100, + child: TestPlatformView(), + ), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + + testWidgets('RenderSnapshotWidget does not take a snapshot if a platform view is encounted with SnapshotMode.permissive', (WidgetTester tester) async { + final SnapshotController controller = SnapshotController(allowSnapshotting: true); + await tester.pumpWidget( + Center( + child: TestDependencies( + child: SnapshotWidget( + controller: controller, + mode: SnapshotMode.permissive, + child: const SizedBox( + width: 100, + height: 100, + child: TestPlatformView(), + ), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + expect(tester.layers.last, isA()); + }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 +} + +class TestController extends SnapshotController { + int addedListenerCount = 0; + int removedListenerCount = 0; + + @override + void addListener(ui.VoidCallback listener) { + addedListenerCount += 1; + super.addListener(listener); + } + + @override + void removeListener(ui.VoidCallback listener) { + removedListenerCount += 1; + super.removeListener(listener); + } +} + +class TestPlatformView extends SingleChildRenderObjectWidget { + const TestPlatformView({super.key}); + + @override + RenderObject createRenderObject(BuildContext context) { + return RenderTestPlatformView(); + } +} + +class RenderTestPlatformView extends RenderProxyBox { + @override + void paint(PaintingContext context, ui.Offset offset) { + context.addLayer(PlatformViewLayer(rect: offset & size, viewId: 1)); + } +} + +class TestPainter extends SnapshotPainter { + int count = 0; + bool shouldRepaintValue = false; + ui.Image? lastImage; + + int addedListenerCount = 0; + int removedListenerCount = 0; + + @override + void addListener(ui.VoidCallback listener) { + addedListenerCount += 1; + super.addListener(listener); + } + + @override + void removeListener(ui.VoidCallback listener) { + removedListenerCount += 1; + super.removeListener(listener); + } + + void notify() { + notifyListeners(); + } + + @override + void paintSnapshot(PaintingContext context, Offset offset, Size size, ui.Image image, double pixelRatio) { + count += 1; + lastImage = image; + } + + @override + void paint(PaintingContext context, ui.Offset offset, ui.Size size, PaintingContextCallback painter) { + count += 1; + } + + @override + bool shouldRepaint(covariant TestPainter oldDelegate) => shouldRepaintValue; +} + +class TestPainter2 extends TestPainter { + @override + bool shouldRepaint(covariant TestPainter2 oldDelegate) => shouldRepaintValue; +} + +class TestDependencies extends StatelessWidget { + const TestDependencies({required this.child, super.key, this.devicePixelRatio}); + + final Widget child; + final double? devicePixelRatio; + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(WidgetsBinding.instance.window) + .copyWith(devicePixelRatio: devicePixelRatio), + child: child, + ), + ); + } +} diff --git a/packages/flutter/test/widgets/tap_region_test.dart b/packages/flutter/test/widgets/tap_region_test.dart index f8b687bc97b65..f83fa0de2dd68 100644 --- a/packages/flutter/test/widgets/tap_region_test.dart +++ b/packages/flutter/test/widgets/tap_region_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('TapRegionSurface detects outside taps', (WidgetTester tester) async { - final Set clickedOutside = {}; + final Set tappedOutside = {}; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -22,21 +22,21 @@ void main() { const Text('Outside'), TapRegion( onTapOutside: (PointerEvent event) { - clickedOutside.add('No Group'); + tappedOutside.add('No Group'); }, child: const Text('No Group'), ), TapRegion( groupId: 1, onTapOutside: (PointerEvent event) { - clickedOutside.add('Group 1 A'); + tappedOutside.add('Group 1 A'); }, child: const Text('Group 1 A'), ), TapRegion( groupId: 1, onTapOutside: (PointerEvent event) { - clickedOutside.add('Group 1 B'); + tappedOutside.add('Group 1 B'); }, child: const Text('Group 1 B'), ), @@ -59,48 +59,48 @@ void main() { await gesture.removePointer(); } - expect(clickedOutside, isEmpty); + expect(tappedOutside, isEmpty); await click(find.text('No Group')); expect( - clickedOutside, + tappedOutside, unorderedEquals({ 'Group 1 A', 'Group 1 B', })); - clickedOutside.clear(); + tappedOutside.clear(); await click(find.text('Group 1 A')); expect( - clickedOutside, + tappedOutside, equals({ 'No Group', })); - clickedOutside.clear(); + tappedOutside.clear(); await click(find.text('Group 1 B')); expect( - clickedOutside, + tappedOutside, equals({ 'No Group', })); - clickedOutside.clear(); + tappedOutside.clear(); await click(find.text('Outside')); expect( - clickedOutside, + tappedOutside, unorderedEquals({ 'No Group', 'Group 1 A', 'Group 1 B', })); - clickedOutside.clear(); + tappedOutside.clear(); await click(find.text('Outside Surface')); - expect(clickedOutside, isEmpty); + expect(tappedOutside, isEmpty); }); testWidgets('TapRegionSurface detects inside taps', (WidgetTester tester) async { - final Set clickedInside = {}; + final Set tappedInside = {}; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -113,21 +113,21 @@ void main() { const Text('Outside'), TapRegion( onTapInside: (PointerEvent event) { - clickedInside.add('No Group'); + tappedInside.add('No Group'); }, child: const Text('No Group'), ), TapRegion( groupId: 1, onTapInside: (PointerEvent event) { - clickedInside.add('Group 1 A'); + tappedInside.add('Group 1 A'); }, child: const Text('Group 1 A'), ), TapRegion( groupId: 1, onTapInside: (PointerEvent event) { - clickedInside.add('Group 1 B'); + tappedInside.add('Group 1 B'); }, child: const Text('Group 1 B'), ), @@ -150,39 +150,139 @@ void main() { await gesture.removePointer(); } - expect(clickedInside, isEmpty); + expect(tappedInside, isEmpty); await click(find.text('No Group')); expect( - clickedInside, + tappedInside, unorderedEquals({ 'No Group', })); - clickedInside.clear(); + tappedInside.clear(); await click(find.text('Group 1 A')); expect( - clickedInside, + tappedInside, equals({ 'Group 1 A', 'Group 1 B', })); - clickedInside.clear(); + tappedInside.clear(); await click(find.text('Group 1 B')); expect( - clickedInside, + tappedInside, equals({ 'Group 1 A', 'Group 1 B', })); - clickedInside.clear(); + tappedInside.clear(); await click(find.text('Outside')); - expect(clickedInside, isEmpty); - clickedInside.clear(); + expect(tappedInside, isEmpty); + tappedInside.clear(); await click(find.text('Outside Surface')); - expect(clickedInside, isEmpty); + expect(tappedInside, isEmpty); + }); + testWidgets('Setting the group updates the registration', (WidgetTester tester) async { + final Set tappedOutside = {}; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: TapRegionSurface( + child: Row( + children: [ + const Text('Outside'), + TapRegion( + groupId: 1, + onTapOutside: (PointerEvent event) { + tappedOutside.add('Group 1 A'); + }, + child: const Text('Group 1 A'), + ), + TapRegion( + groupId: 1, + onTapOutside: (PointerEvent event) { + tappedOutside.add('Group 1 B'); + }, + child: const Text('Group 1 B'), + ), + ], + ), + ), + ), + ); + + await tester.pump(); + + Future click(Finder finder) async { + final TestGesture gesture = await tester.startGesture( + tester.getCenter(finder), + kind: PointerDeviceKind.mouse, + ); + await gesture.up(); + await gesture.removePointer(); + } + + expect(tappedOutside, isEmpty); + + await click(find.text('Group 1 A')); + expect(tappedOutside, isEmpty); + await click(find.text('Group 1 B')); + expect(tappedOutside, isEmpty); + await click(find.text('Outside')); + expect( + tappedOutside, + equals([ + 'Group 1 A', + 'Group 1 B', + ])); + tappedOutside.clear(); + + // Now change out the groups. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: TapRegionSurface( + child: Row( + children: [ + const Text('Outside'), + TapRegion( + groupId: 1, + onTapOutside: (PointerEvent event) { + tappedOutside.add('Group 1 A'); + }, + child: const Text('Group 1 A'), + ), + TapRegion( + groupId: 2, + onTapOutside: (PointerEvent event) { + tappedOutside.add('Group 2 A'); + }, + child: const Text('Group 2 A'), + ), + ], + ), + ), + ), + ); + + await click(find.text('Group 1 A')); + expect(tappedOutside, equals(['Group 2 A'])); + tappedOutside.clear(); + + await click(find.text('Group 2 A')); + expect(tappedOutside, equals(['Group 1 A'])); + tappedOutside.clear(); + + await click(find.text('Outside')); + expect( + tappedOutside, + equals([ + 'Group 1 A', + 'Group 2 A', + ])); + tappedOutside.clear(); }); } diff --git a/packages/flutter/test_fixes/material.dart b/packages/flutter/test_fixes/material.dart index 312a7729adf8b..cdd40e0cb5ba8 100644 --- a/packages/flutter/test_fixes/material.dart +++ b/packages/flutter/test_fixes/material.dart @@ -516,7 +516,7 @@ void main() { colorScheme = ColorScheme.highContrastLight(primaryVariant: Colors.black, secondaryVariant: Colors.white); colorScheme = ColorScheme.highContrastDark(primaryVariant: Colors.black, secondaryVariant: Colors.white); colorScheme = colorScheme.copyWith(primaryVariant: Colors.black, secondaryVariant: Colors.white); - colorScheme.primaryVariant; + colorScheme.primaryVariant; // Removing field reference not supported. colorScheme.secondaryVariant; // Changes made in https://github.com/flutter/flutter/pull/96115 @@ -592,4 +592,100 @@ void main() { themeData = ThemeData.raw(selectedRowColor: Brightness.dark); themeData = themeData.copyWith(selectedRowColor: Brightness.dark); themeData.selectedRowColor; // Removing field reference not supported. + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var TextTheme textTheme = TextTheme( + headline1: headline1Style, + headline2: headline2Style, + headline3: headline3Style, + headline4: headline4Style, + headline5: headline5Style, + headline6: headline6Style, + subtitle1: subtitle1Style, + subtitle2: subtitle2Style, + bodyText1: bodyText1Style, + bodyText2: bodyText2Style, + caption: captionStyle, + button: buttonStyle, + overline: overlineStyle, + ); + var TextTheme textTheme = TextTheme(error: ''); + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var TextTheme copiedTextTheme = TextTheme.copyWith( + headline1: headline1Style, + headline2: headline2Style, + headline3: headline3Style, + headline4: headline4Style, + headline5: headline5Style, + headline6: headline6Style, + subtitle1: subtitle1Style, + subtitle2: subtitle2Style, + bodyText1: bodyText1Style, + bodyText2: bodyText2Style, + caption: captionStyle, + button: buttonStyle, + overline: overlineStyle, + ); + var TextTheme copiedTextTheme = TextTheme.copyWith(error: ''); + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var style; + style = textTheme.headline1; + style = textTheme.headline2; + style = textTheme.headline3; + style = textTheme.headline4; + style = textTheme.headline5; + style = textTheme.headline6; + style = textTheme.subtitle1; + style = textTheme.subtitle2; + style = textTheme.bodyText1; + style = textTheme.bodyText2; + style = textTheme.caption; + style = textTheme.button; + style = textTheme.overline; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(errorColor: Colors.red); + themeData = ThemeData(errorColor: Colors.red, primarySwatch: Colors.blue); + themeData = ThemeData(errorColor: Colors.red, colorScheme: ColorScheme.light()); + themeData = ThemeData(errorColor: Colors.red, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData = ThemeData(otherParam: ''); + themeData = ThemeData.raw(errorColor: Colors.red); + themeData = ThemeData.raw(errorColor: Colors.red, primarySwatch: Colors.blue); + themeData = ThemeData.raw(errorColor: Colors.red, colorScheme: ColorScheme.light()); + themeData = ThemeData.raw(errorColor: Colors.red, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData = ThemeData.raw(otherParam: ''); + themeData = themeData.copyWith(errorColor: Colors.red); + themeData = themeData.copyWith(otherParam: ''); + themeData = themeData.copyWith(errorColor: Colors.red, primarySwatch: Colors.blue); + themeData = themeData.copyWith(errorColor: Colors.red, colorScheme: ColorScheme.light()); + themeData = themeData.copyWith(errorColor: Colors.red, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData.errorColor; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(backgroundColor: Colors.grey); + themeData = ThemeData(backgroundColor: Colors.grey, primarySwatch: Colors.blue); + themeData = ThemeData(backgroundColor: Colors.grey, colorScheme: ColorScheme.light()); + themeData = ThemeData(backgroundColor: Colors.grey, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData = ThemeData(otherParam: ''); + themeData = ThemeData.raw(backgroundColor: Colors.grey); + themeData = ThemeData.raw(backgroundColor: Colors.grey, primarySwatch: Colors.blue); + themeData = ThemeData.raw(backgroundColor: Colors.grey, colorScheme: ColorScheme.light()); + themeData = ThemeData.raw(backgroundColor: Colors.grey, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData = ThemeData.raw(otherParam: ''); + themeData = themeData.copyWith(backgroundColor: Colors.grey); + themeData = themeData.copyWith(otherParam: ''); + themeData = themeData.copyWith(backgroundColor: Colors.grey, primarySwatch: Colors.blue); + themeData = themeData.copyWith(backgroundColor: Colors.grey, colorScheme: ColorScheme.light()); + themeData = themeData.copyWith(backgroundColor: Colors.grey, colorScheme: ColorScheme.light(), primarySwatch: Colors.blue); + themeData.backgroundColor; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(backgroundColor: Colors.grey, errorColor: Colors.red); + themeData = ThemeData.raw(backgroundColor: Colors.grey, errorColor: Colors.red); + themeData = themeData.copyWith(backgroundColor: Colors.grey, errorColor: Colors.red); } diff --git a/packages/flutter/test_fixes/material.dart.expect b/packages/flutter/test_fixes/material.dart.expect index 4f2f9ba7d44bf..4e06598edfbb3 100644 --- a/packages/flutter/test_fixes/material.dart.expect +++ b/packages/flutter/test_fixes/material.dart.expect @@ -80,55 +80,56 @@ void main() { // Changes made in https://github.com/flutter/flutter/pull/48547 var TextTheme textTheme = TextTheme( - headline1: displayStyle4, - headline2: displayStyle3, - headline3: displayStyle2, - headline4: displayStyle1, - headline5: headlineStyle, - headline6: titleStyle, - subtitle1: subheadStyle, - bodyText1: body2Style, - bodyText2: body1Style, - caption: captionStyle, - button: buttonStyle, - subtitle2: subtitleStyle, - overline: overlineStyle, + displayLarge: displayStyle4, + displayMedium: displayStyle3, + displaySmall: displayStyle2, + headlineMedium: displayStyle1, + headlineSmall: headlineStyle, + titleLarge: titleStyle, + titleMedium: subheadStyle, + bodyLarge: body2Style, + bodyMedium: body1Style, + bodySmall: captionStyle, + labelLarge: buttonStyle, + titleSmall: subtitleStyle, + labelSmall: overlineStyle, ); var TextTheme textTheme = TextTheme(error: ''); // Changes made in https://github.com/flutter/flutter/pull/48547 var TextTheme copiedTextTheme = TextTheme.copyWith( - headline1: displayStyle4, - headline2: displayStyle3, - headline3: displayStyle2, - headline4: displayStyle1, - headline5: headlineStyle, - headline6: titleStyle, - subtitle1: subheadStyle, - bodyText1: body2Style, - bodyText2: body1Style, - caption: captionStyle, - button: buttonStyle, - subtitle2: subtitleStyle, - overline: overlineStyle, + displayLarge: displayStyle4, + displayMedium: displayStyle3, + displaySmall: displayStyle2, + headlineMedium: displayStyle1, + headlineSmall: headlineStyle, + titleLarge: titleStyle, + titleMedium: subheadStyle, + bodyLarge: body2Style, + bodyMedium: body1Style, + bodySmall: captionStyle, + labelLarge: buttonStyle, + titleSmall: subtitleStyle, + labelSmall: overlineStyle, ); var TextTheme copiedTextTheme = TextTheme.copyWith(error: ''); // Changes made in https://github.com/flutter/flutter/pull/48547 var style; - style = textTheme.headline1; - style = textTheme.headline2; - style = textTheme.headline3; - style = textTheme.headline4; - style = textTheme.headline5; - style = textTheme.headline6; - style = textTheme.subtitle1; - style = textTheme.bodyText1; - style = textTheme.bodyText2; - style = textTheme.caption; - style = textTheme.button; - style = textTheme.subtitle2; - style = textTheme.overline; + style = textTheme.displayLarge; + style = textTheme.displayMedium; + style = textTheme.displaySmall; + style = textTheme.headlineMedium; + style = textTheme.headlineSmall; + style = textTheme.titleLarge; + style = textTheme.titleMedium; + style = textTheme.bodyLarge; + style = textTheme.bodyMedium; + style = textTheme.bodySmall; + style = textTheme.labelLarge; + style = textTheme.titleSmall; + style = textTheme.labelSmall; + // Changes made in https://github.com/flutter/flutter/pull/68736 MediaQuery.maybeOf(context); @@ -441,18 +442,18 @@ void main() { TextTheme myTextTheme = TextTheme(); AppBar appBar = AppBar(); - appBar = AppBar(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); - appBar = AppBar(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); + appBar = AppBar(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); + appBar = AppBar(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); SliverAppBar sliverAppBar = SliverAppBar(); - sliverAppBar = SliverAppBar(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); - sliverAppBar = SliverAppBar(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); + sliverAppBar = SliverAppBar(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); + sliverAppBar = SliverAppBar(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); AppBarTheme appBarTheme = AppBarTheme(); - appBarTheme = AppBarTheme(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); - appBarTheme = AppBarTheme(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); - appBarTheme = appBarTheme.copyWith(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); - appBarTheme = appBarTheme.copyWith(toolbarTextStyle: myTextTheme.bodyText2, titleTextStyle: myTextTheme.headline6); + appBarTheme = AppBarTheme(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); + appBarTheme = AppBarTheme(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); + appBarTheme = appBarTheme.copyWith(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); + appBarTheme = appBarTheme.copyWith(toolbarTextStyle: myTextTheme.bodyMedium, titleTextStyle: myTextTheme.titleLarge); AppBar appBar = AppBar(); appBar = AppBar(); @@ -489,7 +490,7 @@ void main() { colorScheme = ColorScheme.highContrastLight(); colorScheme = ColorScheme.highContrastDark(); colorScheme = colorScheme.copyWith(); - colorScheme.primaryContainer; + colorScheme.primaryContainer; // Removing field reference not supported. colorScheme.secondaryContainer; // Changes made in https://github.com/flutter/flutter/pull/96115 @@ -795,4 +796,100 @@ void main() { themeData = ThemeData.raw(); themeData = themeData.copyWith(); themeData.selectedRowColor; // Removing field reference not supported. + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var TextTheme textTheme = TextTheme( + displayLarge: headline1Style, + displayMedium: headline2Style, + displaySmall: headline3Style, + headlineMedium: headline4Style, + headlineSmall: headline5Style, + titleLarge: headline6Style, + titleMedium: subtitle1Style, + titleSmall: subtitle2Style, + bodyLarge: bodyText1Style, + bodyMedium: bodyText2Style, + bodySmall: captionStyle, + labelLarge: buttonStyle, + labelSmall: overlineStyle, + ); + var TextTheme textTheme = TextTheme(error: ''); + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var TextTheme copiedTextTheme = TextTheme.copyWith( + displayLarge: headline1Style, + displayMedium: headline2Style, + displaySmall: headline3Style, + headlineMedium: headline4Style, + headlineSmall: headline5Style, + titleLarge: headline6Style, + titleMedium: subtitle1Style, + titleSmall: subtitle2Style, + bodyLarge: bodyText1Style, + bodyMedium: bodyText2Style, + bodySmall: captionStyle, + labelLarge: buttonStyle, + labelSmall: overlineStyle, + ); + var TextTheme copiedTextTheme = TextTheme.copyWith(error: ''); + + // Changes made in https://github.com/flutter/flutter/pull/109817 + var style; + style = textTheme.displayLarge; + style = textTheme.displayMedium; + style = textTheme.displaySmall; + style = textTheme.headlineMedium; + style = textTheme.headlineSmall; + style = textTheme.titleLarge; + style = textTheme.titleMedium; + style = textTheme.titleSmall; + style = textTheme.bodyLarge; + style = textTheme.bodyMedium; + style = textTheme.bodySmall; + style = textTheme.labelLarge; + style = textTheme.labelSmall; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(colorScheme: ColorScheme(error: Colors.red)); + themeData = ThemeData(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(error: Colors.red)); + themeData = ThemeData(colorScheme: ColorScheme.light().copyWith(error: Colors.red)); + themeData = ThemeData(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, error: Colors.red)); + themeData = ThemeData(otherParam: ''); + themeData = ThemeData.raw(colorScheme: ColorScheme(error: Colors.red)); + themeData = ThemeData.raw(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(error: Colors.red)); + themeData = ThemeData.raw(colorScheme: ColorScheme.light().copyWith(error: Colors.red)); + themeData = ThemeData.raw(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, error: Colors.red)); + themeData = ThemeData.raw(otherParam: ''); + themeData = themeData.copyWith(colorScheme: ColorScheme(error: Colors.red)); + themeData = themeData.copyWith(otherParam: ''); + themeData = themeData.copyWith(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(error: Colors.red)); + themeData = themeData.copyWith(colorScheme: ColorScheme.light().copyWith(error: Colors.red)); + themeData = themeData.copyWith(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, error: Colors.red)); + themeData.colorScheme.error; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(colorScheme: ColorScheme(background: Colors.grey)); + themeData = ThemeData(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(background: Colors.grey)); + themeData = ThemeData(colorScheme: ColorScheme.light().copyWith(background: Colors.grey)); + themeData = ThemeData(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, background: Colors.grey)); + themeData = ThemeData(otherParam: ''); + themeData = ThemeData.raw(colorScheme: ColorScheme(background: Colors.grey)); + themeData = ThemeData.raw(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(background: Colors.grey)); + themeData = ThemeData.raw(colorScheme: ColorScheme.light().copyWith(background: Colors.grey)); + themeData = ThemeData.raw(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, background: Colors.grey)); + themeData = ThemeData.raw(otherParam: ''); + themeData = themeData.copyWith(colorScheme: ColorScheme(background: Colors.grey)); + themeData = themeData.copyWith(otherParam: ''); + themeData = themeData.copyWith(colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue).copyWith(background: Colors.grey)); + themeData = themeData.copyWith(colorScheme: ColorScheme.light().copyWith(background: Colors.grey)); + themeData = themeData.copyWith(colorScheme: ColorScheme.light().copyWith(primarySwatch: Colors.blue, background: Colors.grey)); + themeData.colorScheme.background; + + // Changes made in https://github.com/flutter/flutter/pull/110162 + ThemeData themeData = ThemeData(); + themeData = ThemeData(colorScheme: ColorScheme(error: Colors.red).copyWith(background: Colors.grey)); + themeData = ThemeData.raw(colorScheme: ColorScheme(error: Colors.red).copyWith(background: Colors.grey)); + themeData = themeData.copyWith(colorScheme: ColorScheme(error: Colors.red).copyWith(background: Colors.grey)); } diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 4c9fcb7872366..43725f7538a9d 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a75e +# PUBSPEC CHECKSUM: 395f diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 53e767871f1f6..b5d9282acb47f 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: characters: 1.2.1 collection: 1.16.0 meta: 1.8.0 - vector_math: 2.1.2 + vector_math: 2.1.3 async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,15 +27,15 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6db4 +# PUBSPEC CHECKSUM: 5eb7 diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index b364277d33e8c..cd7451c2998cc 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -20,6 +20,16 @@ import 'vsync_frame_lag_summarizer.dart'; const JsonEncoder _prettyEncoder = JsonEncoder.withIndent(' '); +const String _kEmptyDurationMessage = r''' +The TimelineSummary had no events to summarize. + +This can happen if the timeline summarization covered too short of a period +or if the driver script failed to interact with the application to generate +events. For example, if your driver script contained only a "driver.scroll()" +command but the app under test was not scrollable then no events would be +generated by the interaction. +'''; + /// The maximum amount of time considered safe to spend for a frame's build /// phase. Anything past that is in the danger of missing the frame as 60FPS. const Duration kBuildBudget = Duration(milliseconds: 16); @@ -40,21 +50,21 @@ class TimelineSummary { /// Average amount of time spent per frame in the framework building widgets, /// updating layout, painting and compositing. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computeAverageFrameBuildTimeMillis() { return _averageInMillis(_extractFrameDurations()); } /// The [p]-th percentile frame rasterization time in milliseconds. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computePercentileFrameBuildTimeMillis(double p) { return _percentileInMillis(_extractFrameDurations(), p); } /// The longest frame build time in milliseconds. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computeWorstFrameBuildTimeMillis() { return _maxInMillis(_extractFrameDurations()); } @@ -67,21 +77,21 @@ class TimelineSummary { /// Average amount of time spent per frame in the engine rasterizer. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computeAverageFrameRasterizerTimeMillis() { return _averageInMillis(_extractGpuRasterizerDrawDurations()); } /// The longest frame rasterization time in milliseconds. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computeWorstFrameRasterizerTimeMillis() { return _maxInMillis(_extractGpuRasterizerDrawDurations()); } /// The [p]-th percentile frame rasterization time in milliseconds. /// - /// Returns null if no frames were recorded. + /// Throws a [StateError] if this summary contains no timeline events. double computePercentileFrameRasterizerTimeMillis(double p) { return _percentileInMillis(_extractGpuRasterizerDrawDurations(), p); } @@ -409,26 +419,26 @@ class TimelineSummary { return result; } - double _averageInMillis(Iterable durations) { + double _averageInMillis(List durations) { if (durations.isEmpty) { - throw ArgumentError('durations is empty!'); + throw StateError(_kEmptyDurationMessage); } final double total = durations.fold(0.0, (double t, Duration duration) => t + duration.inMicroseconds.toDouble() / 1000.0); return total / durations.length; } - double _percentileInMillis(Iterable durations, double percentile) { + double _percentileInMillis(List durations, double percentile) { if (durations.isEmpty) { - throw ArgumentError('durations is empty!'); + throw StateError(_kEmptyDurationMessage); } assert(percentile >= 0.0 && percentile <= 100.0); final List doubles = durations.map((Duration duration) => duration.inMicroseconds.toDouble() / 1000.0).toList(); return findPercentile(doubles, percentile); } - double _maxInMillis(Iterable durations) { + double _maxInMillis(List durations) { if (durations.isEmpty) { - throw ArgumentError('durations is empty!'); + throw StateError(_kEmptyDurationMessage); } return durations .map((Duration duration) => duration.inMicroseconds.toDouble() / 1000.0) diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 11ad247d77c2d..d5c62fd3932dc 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -6,7 +6,7 @@ environment: sdk: ">=2.17.0-0 <3.0.0" dependencies: - file: 6.1.3 + file: 6.1.4 flutter: sdk: flutter flutter_test: @@ -35,20 +35,20 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.3.1 - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,10 +66,10 @@ dev_dependencies: shelf_web_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2df5 +# PUBSPEC CHECKSUM: cafa diff --git a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart index 3fec56866f34d..b94249191e4e4 100644 --- a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart +++ b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart @@ -159,7 +159,12 @@ void main() { test('throws when there is no data', () { expect( () => summarize(>[]).computeAverageFrameBuildTimeMillis(), - throwsA(predicate((ArgumentError e) => e.message == 'durations is empty!')), + throwsA( + isA() + .having((StateError e) => e.message, + 'message', + contains('The TimelineSummary had no events to summarize.'), + )), ); }); @@ -223,7 +228,12 @@ void main() { test('throws when there is no data', () { expect( () => summarize(>[]).computeWorstFrameBuildTimeMillis(), - throwsA(predicate((ArgumentError e) => e.message == 'durations is empty!')), + throwsA( + isA() + .having((StateError e) => e.message, + 'message', + contains('The TimelineSummary had no events to summarize.'), + )), ); }); @@ -282,7 +292,12 @@ void main() { test('throws when there is no data', () { expect( () => summarize(>[]).computeAverageFrameRasterizerTimeMillis(), - throwsA(predicate((ArgumentError e) => e.message == 'durations is empty!')), + throwsA( + isA() + .having((StateError e) => e.message, + 'message', + contains('The TimelineSummary had no events to summarize.'), + )), ); }); @@ -321,7 +336,12 @@ void main() { test('throws when there is no data', () { expect( () => summarize(>[]).computeWorstFrameRasterizerTimeMillis(), - throwsA(predicate((ArgumentError e) => e.message == 'durations is empty!')), + throwsA( + isA() + .having((StateError e) => e.message, + 'message', + contains('The TimelineSummary had no events to summarize.'), + )), ); }); @@ -368,7 +388,12 @@ void main() { test('throws when there is no data', () { expect( () => summarize(>[]).computePercentileFrameRasterizerTimeMillis(90.0), - throwsA(predicate((ArgumentError e) => e.message == 'durations is empty!')), + throwsA( + isA() + .having((StateError e) => e.message, + 'message', + contains('The TimelineSummary had no events to summarize.'), + )), ); }); diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index 29211dfce5099..22b529467b6d9 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter flutter_goldens_client: path: ../flutter_goldens_client - file: 6.1.3 + file: 6.1.4 meta: 1.8.0 platform: 3.1.0 process: 4.2.4 @@ -31,8 +31,8 @@ dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ba14 +# PUBSPEC CHECKSUM: ef17 diff --git a/packages/flutter_goldens_client/lib/skia_client.dart b/packages/flutter_goldens_client/lib/skia_client.dart index 50322ef27ea2d..b30b736bc339a 100644 --- a/packages/flutter_goldens_client/lib/skia_client.dart +++ b/packages/flutter_goldens_client/lib/skia_client.dart @@ -139,7 +139,7 @@ class SkiaGoldClient { /// backend, the `init` argument initializes the current test. Used by the /// [FlutterPostSubmitFileComparator]. Future imgtestInit() async { - // This client has already been intialized + // This client has already been initialized if (_initialized) { return; } diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index 2cb7f6166b40c..f3926eb0dd2fb 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: # To update these, use "flutter update-packages --force-upgrade". crypto: 3.0.2 - file: 6.1.3 + file: 6.1.4 platform: 3.1.0 process: 4.2.4 @@ -19,4 +19,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 2403 +# PUBSPEC CHECKSUM: ad04 diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index b04d49707c7d0..09eab8148fdb1 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -31,6 +31,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e8f2 +# PUBSPEC CHECKSUM: 0ff4 diff --git a/packages/flutter_localizations/test/basics_test.dart b/packages/flutter_localizations/test/basics_test.dart index 961bceb5f8185..4ac2375a7d0d2 100644 --- a/packages/flutter_localizations/test/basics_test.dart +++ b/packages/flutter_localizations/test/basics_test.dart @@ -22,9 +22,9 @@ void main() { )); final LocalizationTrackerState outerTracker = tester.state(find.byKey(const ValueKey('outer'), skipOffstage: false)); - expect(outerTracker.captionFontSize, 12.0); + expect(outerTracker.bodySmallFontSize, 12.0); final LocalizationTrackerState innerTracker = tester.state(find.byKey(const ValueKey('inner'), skipOffstage: false)); - expect(innerTracker.captionFontSize, 13.0); + expect(innerTracker.bodySmallFontSize, 13.0); }); testWidgets('Localizations is compatible with ChangeNotifier.dispose() called during didChangeDependencies', (WidgetTester tester) async { @@ -92,11 +92,11 @@ class LocalizationTracker extends StatefulWidget { } class LocalizationTrackerState extends State { - late double captionFontSize; + late double bodySmallFontSize; @override Widget build(BuildContext context) { - captionFontSize = Theme.of(context).textTheme.caption!.fontSize!; + bodySmallFontSize = Theme.of(context).textTheme.bodySmall!.fontSize!; return Container(); } } diff --git a/packages/flutter_test/lib/src/animation_sheet.dart b/packages/flutter_test/lib/src/animation_sheet.dart index 3252a94bec9b3..8fe9b4dc29c3e 100644 --- a/packages/flutter_test/lib/src/animation_sheet.dart +++ b/packages/flutter_test/lib/src/animation_sheet.dart @@ -102,7 +102,7 @@ class AnimationSheetBuilder { /// subtree of [record]. /// /// If [allLayers] is false, then the [record] widget will capture the image - /// composited by its subtree. If [allLayers] is true, then the [record] will + /// composited by its subtree. If [allLayers] is true, then the [record] will /// capture the entire tree composited and clipped by [record]'s region. /// /// The two modes are identical if there is nothing in front of [record]. diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart index 89904207c5a23..ded21a6b5c7de 100644 --- a/packages/flutter_test/lib/src/event_simulation.dart +++ b/packages/flutter_test/lib/src/event_simulation.dart @@ -722,7 +722,7 @@ class KeyEventSimulator { // its values. // // The `_transitMode` defaults to [KeyDataTransitMode.rawKeyEvent], and can be - // overridden with [debugKeyEventSimulatorTransitModeOverride]. In widget tests, it + // overridden with [debugKeyEventSimulatorTransitModeOverride]. In widget tests, it // is often set with [KeySimulationModeVariant]. static KeyDataTransitMode get _transitMode { KeyDataTransitMode? result; diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index cad66d3e003b5..8229dca022263 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -500,7 +500,7 @@ AsyncMatcher matchesReferenceImage(ui.Image image) { /// Asserts that a [SemanticsNode] contains the specified information. /// /// If either the label, hint, value, textDirection, or rect fields are not -/// provided, then they are not part of the comparison. All of the boolean +/// provided, then they are not part of the comparison. All of the boolean /// flag and action fields must match, and default to false. /// /// To retrieve the semantics data of a widget, use [WidgetTester.getSemantics] diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index 9e5cf69189ded..c6007e23e0bae 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.4.12 + test_api: 0.4.13 # Used by golden file comparator path: 1.8.2 @@ -27,7 +27,7 @@ dependencies: stack_trace: 1.10.0 # Used by globalToLocal et al. - vector_math: 2.1.2 + vector_math: 2.1.3 async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,6 +42,6 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - file: 6.1.3 + file: 6.1.4 -# PUBSPEC CHECKSUM: 08ad +# PUBSPEC CHECKSUM: beb0 diff --git a/packages/flutter_test/test/accessibility_test.dart b/packages/flutter_test/test/accessibility_test.dart index c0dbb015cb92e..399a33e77fad0 100644 --- a/packages/flutter_test/test/accessibility_test.dart +++ b/packages/flutter_test/test/accessibility_test.dart @@ -43,6 +43,40 @@ void main() { handle.dispose(); }); + testWidgets('White text on white background fails contrast test', + (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + _boilerplate( + Container( + width: 200.0, + height: 300.0, + color: Colors.white, + child: Column( + children: const [ + Text( + 'this is a white text', + style: TextStyle(fontSize: 14.0, color: Colors.white), + ), + SizedBox(height: 50), + Text( + 'this is a black text test1', + style: TextStyle(fontSize: 14.0, color: Colors.black), + ), + SizedBox(height: 50), + Text( + 'this is a black text test2', + style: TextStyle(fontSize: 14.0, color: Colors.black), + ), + ], + ), + ), + ), + ); + await expectLater(tester, doesNotMeetGuideline(textContrastGuideline)); + handle.dispose(); + }); + const Color surface = Color(0xFFF0F0F0); /// Shades of blue with contrast ratio of 2.9, 4.4, 4.5 from [surface]. diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index 944ec4ae074d2..a26aeb5231722 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -127,6 +127,7 @@ Future main(List args) async { }, PreRunValidator: () => PreRunValidator(fileSystem: globals.fs), }, + shutdownHooks: globals.shutdownHooks, ); } @@ -143,7 +144,7 @@ List generateCommands({ terminal: globals.terminal, artifacts: globals.artifacts!, // new ProjectValidators should be added here for the --suggestions to run - allProjectValidators: [], + allProjectValidators: [GeneralInfoProjectValidator()], ), AssembleCommand(verboseHelp: verboseHelp, buildSystem: globals.buildSystem), AttachCommand(verboseHelp: verboseHelp), @@ -178,6 +179,8 @@ List generateCommands({ GenerateLocalizationsCommand( fileSystem: globals.fs, logger: globals.logger, + artifacts: globals.artifacts!, + processManager: globals.processManager, ), InstallCommand(), LogsCommand(), diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index 5c824b6e05ac9..9da36edd0f61d 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -34,6 +34,7 @@ Future run( bool? reportCrashes, String? flutterVersion, Map? overrides, + required ShutdownHooks shutdownHooks, }) async { if (muteCommandLogging) { // Remove the verbose option; for help and doctor, users don't need to see @@ -62,19 +63,19 @@ Future run( await runner.run(args); // Triggering [runZoned]'s error callback does not necessarily mean that - // we stopped executing the body. See https://github.com/dart-lang/sdk/issues/42150. + // we stopped executing the body. See https://github.com/dart-lang/sdk/issues/42150. if (firstError == null) { - return await _exit(0); + return await _exit(0, shutdownHooks: shutdownHooks); } - // We already hit some error, so don't return success. The error path + // We already hit some error, so don't return success. The error path // (which should be in progress) is responsible for calling _exit(). return 1; } catch (error, stackTrace) { // ignore: avoid_catches_without_on_clauses // This catches all exceptions to send to crash logging, etc. firstError = error; firstStackTrace = stackTrace; - return _handleToolError(error, stackTrace, verbose, args, reportCrashes!, getVersion); + return _handleToolError(error, stackTrace, verbose, args, reportCrashes!, getVersion, shutdownHooks); } }, onError: (Object error, StackTrace stackTrace) async { // ignore: deprecated_member_use // If sending a crash report throws an error into the zone, we don't want @@ -82,7 +83,7 @@ Future run( // to send the original error that triggered the crash report. firstError ??= error; firstStackTrace ??= stackTrace; - await _handleToolError(firstError!, firstStackTrace, verbose, args, reportCrashes!, getVersion); + await _handleToolError(firstError!, firstStackTrace, verbose, args, reportCrashes!, getVersion, shutdownHooks); }); }, overrides: overrides); } @@ -94,12 +95,13 @@ Future _handleToolError( List args, bool reportCrashes, String Function() getFlutterVersion, + ShutdownHooks shutdownHooks, ) async { if (error is UsageException) { globals.printError('${error.message}\n'); globals.printError("Run 'flutter -h' (or 'flutter -h') for available flutter commands and options."); // Argument error exit code. - return _exit(64); + return _exit(64, shutdownHooks: shutdownHooks); } else if (error is ToolExit) { if (error.message != null) { globals.printError(error.message!); @@ -107,14 +109,14 @@ Future _handleToolError( if (verbose) { globals.printError('\n$stackTrace\n'); } - return _exit(error.exitCode ?? 1); + return _exit(error.exitCode ?? 1, shutdownHooks: shutdownHooks); } else if (error is ProcessExit) { // We've caught an exit code. if (error.immediate) { exit(error.exitCode); return error.exitCode; } else { - return _exit(error.exitCode); + return _exit(error.exitCode, shutdownHooks: shutdownHooks); } } else { // We've crashed; emit a log report. @@ -124,7 +126,7 @@ Future _handleToolError( // Print the stack trace on the bots - don't write a crash report. globals.stdio.stderrWrite('$error\n'); globals.stdio.stderrWrite('$stackTrace\n'); - return _exit(1); + return _exit(1, shutdownHooks: shutdownHooks); } // Report to both [Usage] and [CrashReportSender]. @@ -165,7 +167,7 @@ Future _handleToolError( final File file = await _createLocalCrashReport(details); await globals.crashReporter!.informUser(details, file); - return _exit(1); + return _exit(1, shutdownHooks: shutdownHooks); // This catch catches all exceptions to ensure the message below is printed. } catch (error, st) { // ignore: avoid_catches_without_on_clauses globals.stdio.stderrWrite( @@ -228,7 +230,7 @@ Future _createLocalCrashReport(CrashDetails details) async { return crashFile; } -Future _exit(int code) async { +Future _exit(int code, {required ShutdownHooks shutdownHooks}) async { // Prints the welcome message if needed. globals.flutterUsage.printWelcome(); @@ -241,7 +243,7 @@ Future _exit(int code) async { } // Run shutdown hooks before flushing logs - await globals.shutdownHooks!.runShutdownHooks(); + await shutdownHooks.runShutdownHooks(globals.logger); final Completer completer = Completer(); diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index fd7a64297d930..f509b562352cf 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -20,7 +20,6 @@ import '../device.dart'; import '../device_port_forwarder.dart'; import '../project.dart'; import '../protocol_discovery.dart'; - import 'android.dart'; import 'android_builder.dart'; import 'android_console.dart'; @@ -313,7 +312,7 @@ class AndroidDevice extends Device { try { // If the server is automatically restarted, then we get irrelevant // output lines like this, which we want to ignore: - // adb server is out of date. killing.. + // adb server is out of date. killing.. // * daemon started successfully * await _processUtils.run( [adbPath, 'start-server'], diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index c539d67156f56..a8aadef1a9ff5 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -732,6 +732,8 @@ abstract class LocalEngineArtifacts implements Artifacts { }) = CachedLocalEngineArtifacts; String get engineOutPath; + + String get localEngineName; } /// Manages the artifacts of a locally built engine. @@ -745,6 +747,7 @@ class CachedLocalEngineArtifacts implements LocalEngineArtifacts { required Platform platform, required OperatingSystemUtils operatingSystemUtils, }) : _fileSystem = fileSystem, + localEngineName = fileSystem.path.basename(engineOutPath), _cache = cache, _processManager = processManager, _platform = platform, @@ -753,6 +756,9 @@ class CachedLocalEngineArtifacts implements LocalEngineArtifacts { @override final String engineOutPath; + @override + final String localEngineName; + final String _hostEngineOutPath; final FileSystem _fileSystem; final Cache _cache; @@ -1063,4 +1069,7 @@ class _TestLocalEngine extends _TestArtifacts implements LocalEngineArtifacts { @override final String engineOutPath; + + @override + String get localEngineName => fileSystem.path.basename(engineOutPath); } diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index 9dd7272fbefbc..c7e438ca6abb3 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart @@ -270,7 +270,7 @@ class ManifestAssetBundle implements AssetBundle { return 1; } - // Parse assets for deferred components. + // Parse assets for deferred components. final Map>> deferredComponentsAssetVariants = _parseDeferredComponentsAssets( flutterManifest, packageConfig, diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index 96600b4889303..08d326848e304 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -139,10 +139,17 @@ class AOTSnapshotter { '--deterministic', ]; + final bool targetingApplePlatform = + platform == TargetPlatform.ios || platform == TargetPlatform.darwin; + _logger.printTrace('targetingApplePlatform = $targetingApplePlatform'); + + final bool extractAppleDebugSymbols = + buildMode == BuildMode.profile || buildMode == BuildMode.release; + _logger.printTrace('extractAppleDebugSymbols = $extractAppleDebugSymbols'); + // We strip snapshot by default, but allow to suppress this behavior // by supplying --no-strip in extraGenSnapshotOptions. bool shouldStrip = true; - if (extraGenSnapshotOptions != null && extraGenSnapshotOptions.isNotEmpty) { _logger.printTrace('Extra gen_snapshot options: $extraGenSnapshotOptions'); for (final String option in extraGenSnapshotOptions) { @@ -168,8 +175,20 @@ class AOTSnapshotter { ]); } - if (shouldStrip) { - genSnapshotArgs.add('--strip'); + // When buiding for iOS and splitting out debug info, we want to strip + // manually after the dSYM export, instead of in the `gen_snapshot`. + final bool stripAfterBuild; + if (targetingApplePlatform) { + stripAfterBuild = shouldStrip; + if (stripAfterBuild) { + _logger.printTrace('Will strip AOT snapshot manual after build and dSYM generation.'); + } + } else { + stripAfterBuild = false; + if (shouldStrip) { + genSnapshotArgs.add('--strip'); + _logger.printTrace('Will strip AOT snapshot during build.'); + } } if (platform == TargetPlatform.android_arm) { @@ -218,8 +237,8 @@ class AOTSnapshotter { // On iOS and macOS, we use Xcode to compile the snapshot into a dynamic library that the // end-developer can link into their app. - if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin) { - final RunResult result = await _buildFramework( + if (targetingApplePlatform) { + return _buildFramework( appleArch: darwinArch!, isIOS: platform == TargetPlatform.ios, sdkRoot: sdkRoot, @@ -227,24 +246,26 @@ class AOTSnapshotter { outputPath: outputDir.path, bitcode: bitcode, quiet: quiet, + stripAfterBuild: stripAfterBuild, + extractAppleDebugSymbols: extractAppleDebugSymbols ); - if (result.exitCode != 0) { - return result.exitCode; - } + } else { + return 0; } - return 0; } /// Builds an iOS or macOS framework at [outputPath]/App.framework from the assembly /// source at [assemblyPath]. - Future _buildFramework({ + Future _buildFramework({ required DarwinArch appleArch, required bool isIOS, String? sdkRoot, required String assemblyPath, required String outputPath, required bool bitcode, - required bool quiet + required bool quiet, + required bool stripAfterBuild, + required bool extractAppleDebugSymbols }) async { final String targetArch = getNameForDarwinArch(appleArch); if (!quiet) { @@ -278,7 +299,7 @@ class AOTSnapshotter { ]); if (compileResult.exitCode != 0) { _logger.printError('Failed to compile AOT snapshot. Compiler terminated with exit code ${compileResult.exitCode}'); - return compileResult; + return compileResult.exitCode; } final String frameworkDir = _fileSystem.path.join(outputPath, 'App.framework'); @@ -294,11 +315,33 @@ class AOTSnapshotter { '-o', appLib, assemblyO, ]; + final RunResult linkResult = await _xcode.clang(linkArgs); if (linkResult.exitCode != 0) { - _logger.printError('Failed to link AOT snapshot. Linker terminated with exit code ${compileResult.exitCode}'); + _logger.printError('Failed to link AOT snapshot. Linker terminated with exit code ${linkResult.exitCode}'); + return linkResult.exitCode; + } + + if (extractAppleDebugSymbols) { + final RunResult dsymResult = await _xcode.dsymutil(['-o', '$frameworkDir.dSYM', appLib]); + if (dsymResult.exitCode != 0) { + _logger.printError('Failed to generate dSYM - dsymutil terminated with exit code ${dsymResult.exitCode}'); + return dsymResult.exitCode; + } + + if (stripAfterBuild) { + // See https://www.unix.com/man-page/osx/1/strip/ for arguments + final RunResult stripResult = await _xcode.strip(['-S', appLib, '-o', appLib]); + if (stripResult.exitCode != 0) { + _logger.printError('Failed to strip debugging symbols from the generated AOT snapshot - strip terminated with exit code ${stripResult.exitCode}'); + return stripResult.exitCode; + } + } + } else { + assert(stripAfterBuild == false); } - return linkResult; + + return 0; } bool _isValidAotPlatform(TargetPlatform platform, BuildMode buildMode) { diff --git a/packages/flutter_tools/lib/src/base/dds.dart b/packages/flutter_tools/lib/src/base/dds.dart index fd01ddbfb9a9d..00ddabd74118f 100644 --- a/packages/flutter_tools/lib/src/base/dds.dart +++ b/packages/flutter_tools/lib/src/base/dds.dart @@ -12,6 +12,7 @@ import 'context.dart'; import 'io.dart' as io; import 'logger.dart'; +// TODO(fujino): This should be direct injected, rather than mutable global state. @visibleForTesting Future Function( Uri remoteVmServiceUri, { diff --git a/packages/flutter_tools/lib/src/base/file_system.dart b/packages/flutter_tools/lib/src/base/file_system.dart index 7feb83fea14e5..5580289034298 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -177,17 +177,18 @@ File getUniqueFile(Directory dir, String baseName, String ext) { /// directories and files that the tool creates under the system temporary /// directory when the tool exits either normally or when killed by a signal. class LocalFileSystem extends local_fs.LocalFileSystem { - LocalFileSystem(this._signals, this._fatalSignals, this._shutdownHooks); + LocalFileSystem(this._signals, this._fatalSignals, this.shutdownHooks); @visibleForTesting LocalFileSystem.test({ required Signals signals, List fatalSignals = Signals.defaultExitSignals, - }) : this(signals, fatalSignals, null); + }) : this(signals, fatalSignals, ShutdownHooks()); Directory? _systemTemp; final Map _signalTokens = {}; - final ShutdownHooks? _shutdownHooks; + + final ShutdownHooks shutdownHooks; Future dispose() async { _tryToDeleteTemp(); @@ -206,7 +207,7 @@ class LocalFileSystem extends local_fs.LocalFileSystem { _systemTemp?.deleteSync(recursive: true); } } on FileSystemException { - // ignore. + // ignore } _systemTemp = null; } @@ -239,7 +240,7 @@ class LocalFileSystem extends local_fs.LocalFileSystem { } // Make sure that the temporary directory is cleaned up when the tool // exits normally. - _shutdownHooks?.addShutdownHook( + shutdownHooks.addShutdownHook( _tryToDeleteTemp, ); } diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index 506680dc4cad4..f80aed9bfd75e 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -1198,7 +1198,7 @@ class SilentStatus extends Status { const int _kTimePadding = 8; // should fit "99,999ms" -/// Constructor writes [message] to [stdout]. On [cancel] or [stop], will call +/// Constructor writes [message] to [stdout]. On [cancel] or [stop], will call /// [onFinish]. On [stop], will additionally print out summary information. class SummaryStatus extends Status { SummaryStatus({ diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index 84ec6768b6434..f4d3a9fff51d9 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -377,7 +377,7 @@ class _MacOSUtils extends _PosixUtils { if (results.every((RunResult result) => result.exitCode == 0)) { String osName = getNameForHostPlatform(hostPlatform); // If the script is running in Rosetta, "uname -m" will return x86_64. - if (hostPlatform == HostPlatform.darwin_arm && results[3].stdout.contains('x86_64')) { + if (hostPlatform == HostPlatform.darwin_arm64 && results[3].stdout.contains('x86_64')) { osName = '$osName (Rosetta)'; } _name = @@ -415,7 +415,7 @@ class _MacOSUtils extends _PosixUtils { // On arm64 stdout is "sysctl hw.optional.arm64: 1" // On x86 hw.optional.arm64 is unavailable and exits with 1. if (arm64Check.exitCode == 0 && arm64Check.stdout.trim().endsWith('1')) { - _hostPlatform = HostPlatform.darwin_arm; + _hostPlatform = HostPlatform.darwin_arm64; } else { _hostPlatform = HostPlatform.darwin_x64; } @@ -604,7 +604,7 @@ String? findProjectRoot(FileSystem fileSystem, [ String? directory ]) { enum HostPlatform { darwin_x64, - darwin_arm, + darwin_arm64, linux_x64, linux_arm64, windows_x64, @@ -614,8 +614,8 @@ String getNameForHostPlatform(HostPlatform platform) { switch (platform) { case HostPlatform.darwin_x64: return 'darwin-x64'; - case HostPlatform.darwin_arm: - return 'darwin-arm'; + case HostPlatform.darwin_arm64: + return 'darwin-arm64'; case HostPlatform.linux_x64: return 'linux-x64'; case HostPlatform.linux_arm64: diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart index f37989fb5f37b..5670a075f14d9 100644 --- a/packages/flutter_tools/lib/src/base/process.dart +++ b/packages/flutter_tools/lib/src/base/process.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../convert.dart'; @@ -13,7 +14,7 @@ import 'logger.dart'; typedef StringConverter = String? Function(String string); /// A function that will be run before the VM exits. -typedef ShutdownHook = FutureOr Function(); +typedef ShutdownHook = FutureOr Function(); // TODO(ianh): We have way too many ways to run subprocesses in this project. // Convert most of these into one or more lightweight wrappers around the @@ -22,17 +23,16 @@ typedef ShutdownHook = FutureOr Function(); // for more details. abstract class ShutdownHooks { - factory ShutdownHooks({ - required Logger logger, - }) => _DefaultShutdownHooks( - logger: logger, - ); + factory ShutdownHooks() => _DefaultShutdownHooks(); /// Registers a [ShutdownHook] to be executed before the VM exits. void addShutdownHook( ShutdownHook shutdownHook ); + @visibleForTesting + List get registeredHooks; + /// Runs all registered shutdown hooks and returns a future that completes when /// all such hooks have finished. /// @@ -40,16 +40,17 @@ abstract class ShutdownHooks { /// hooks within a given stage will be started in parallel and will be /// guaranteed to run to completion before shutdown hooks in the next stage are /// started. - Future runShutdownHooks(); + /// + /// This class is constructed before the [Logger], so it cannot be direct + /// injected in the constructor. + Future runShutdownHooks(Logger logger); } class _DefaultShutdownHooks implements ShutdownHooks { - _DefaultShutdownHooks({ - required Logger logger, - }) : _logger = logger; + _DefaultShutdownHooks(); - final Logger _logger; - final List _shutdownHooks = []; + @override + final List registeredHooks = []; bool _shutdownHooksRunning = false; @@ -58,16 +59,18 @@ class _DefaultShutdownHooks implements ShutdownHooks { ShutdownHook shutdownHook ) { assert(!_shutdownHooksRunning); - _shutdownHooks.add(shutdownHook); + registeredHooks.add(shutdownHook); } @override - Future runShutdownHooks() async { - _logger.printTrace('Running shutdown hooks'); + Future runShutdownHooks(Logger logger) async { + logger.printTrace( + 'Running ${registeredHooks.length} shutdown hook${registeredHooks.length == 1 ? '' : 's'}', + ); _shutdownHooksRunning = true; try { final List> futures = >[]; - for (final ShutdownHook shutdownHook in _shutdownHooks) { + for (final ShutdownHook shutdownHook in registeredHooks) { final FutureOr result = shutdownHook(); if (result is Future) { futures.add(result); @@ -77,7 +80,7 @@ class _DefaultShutdownHooks implements ShutdownHooks { } finally { _shutdownHooksRunning = false; } - _logger.printTrace('Shutdown hooks complete'); + logger.printTrace('Shutdown hooks complete'); } } diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 47257c0349bc6..bf4cb6e05531d 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -115,8 +115,8 @@ class UserMessages { 'You can download the JDK from https://www.oracle.com/technetwork/java/javase/downloads/.'; String androidJdkLocation(String location) => 'Java binary at: $location'; String get androidLicensesAll => 'All Android licenses accepted.'; - String get androidLicensesSome => 'Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; - String get androidLicensesNone => 'Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; + String get androidLicensesSome => 'Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; + String get androidLicensesNone => 'Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; String androidLicensesUnknown(Platform platform) => 'Android license status unknown.\n' 'Run `flutter doctor --android-licenses` to accept the SDK licenses.\n' diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index aee345734f39d..6f7a2ab6a2215 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -4,6 +4,7 @@ import 'package:package_config/package_config_types.dart'; +import 'artifacts.dart'; import 'base/config.dart'; import 'base/context.dart'; import 'base/file_system.dart'; @@ -562,8 +563,19 @@ enum AndroidArch { /// The default set of iOS device architectures to build for. List defaultIOSArchsForEnvironment( - EnvironmentType environmentType) { - if (environmentType == EnvironmentType.simulator) { + EnvironmentType environmentType, + Artifacts artifacts, +) { + // Handle single-arch local engines. + if (artifacts is LocalEngineArtifacts) { + final String localEngineName = artifacts.localEngineName; + if (localEngineName.contains('_arm64')) { + return [ DarwinArch.arm64 ]; + } + if (localEngineName.contains('_sim')) { + return [ DarwinArch.x86_64 ]; + } + } else if (environmentType == EnvironmentType.simulator) { return [ DarwinArch.x86_64, DarwinArch.arm64, @@ -574,6 +586,21 @@ List defaultIOSArchsForEnvironment( ]; } +/// The default set of macOS device architectures to build for. +List defaultMacOSArchsForEnvironment(Artifacts artifacts) { + // Handle single-arch local engines. + if (artifacts is LocalEngineArtifacts) { + if (artifacts.localEngineName.contains('_arm64')) { + return [ DarwinArch.arm64 ]; + } + return [ DarwinArch.x86_64 ]; + } + return [ + DarwinArch.x86_64, + DarwinArch.arm64, + ]; +} + // Returns the Dart SDK's name for the specified target architecture. // // When building for Darwin platforms, the tool invokes architecture-specific @@ -594,7 +621,7 @@ String getDartNameForDarwinArch(DarwinArch arch) { // Returns Apple's name for the specified target architecture. // // When invoking Apple tools such as `xcodebuild` or `lipo`, the tool often -// passes one or more target architectures as paramters. The names returned by +// passes one or more target architectures as parameters. The names returned by // this function reflect Apple's name for the specified architecture. // // For consistency with developer expectations, Flutter outputs also use these @@ -696,7 +723,7 @@ TargetPlatform getTargetPlatformForName(String platform) { // For backward-compatibility and also for Tester, where it must match // host platform name (HostPlatform.darwin_x64) case 'darwin-x64': - case 'darwin-arm': + case 'darwin-arm64': return TargetPlatform.darwin; case 'linux-x64': return TargetPlatform.linux_x64; @@ -1034,8 +1061,8 @@ String getNameForHostPlatformArch(HostPlatform platform) { switch (platform) { case HostPlatform.darwin_x64: return 'x64'; - case HostPlatform.darwin_arm: - return 'arm'; + case HostPlatform.darwin_arm64: + return 'arm64'; case HostPlatform.linux_x64: return 'x64'; case HostPlatform.linux_arm64: diff --git a/packages/flutter_tools/lib/src/build_system/file_store.dart b/packages/flutter_tools/lib/src/build_system/file_store.dart index 5045370a601c0..c553569832a65 100644 --- a/packages/flutter_tools/lib/src/build_system/file_store.dart +++ b/packages/flutter_tools/lib/src/build_system/file_store.dart @@ -84,7 +84,7 @@ enum FileStoreStrategy { /// through this class. /// /// This class uses either timestamps or file hashes depending on the -/// provided [FileStoreStrategy]. All information is held in memory during +/// provided [FileStoreStrategy]. All information is held in memory during /// a build operation, and may be persisted to cache in the root build /// directory. /// diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 656f1943dfb6f..753fe683e5ba5 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -7,6 +7,7 @@ import 'package:package_config/package_config.dart'; import '../../artifacts.dart'; import '../../base/build.dart'; import '../../base/file_system.dart'; +import '../../base/io.dart'; import '../../build_info.dart'; import '../../compile.dart'; import '../../dart/package_map.dart'; @@ -394,3 +395,48 @@ abstract class CopyFlutterAotBundle extends Target { environment.buildDir.childFile('app.so').copySync(outputFile.path); } } + +/// Lipo CLI tool wrapper shared by iOS and macOS builds. +class Lipo { + /// Static only. + Lipo._(); + + /// Create a "fat" binary by combining multiple architecture-specific ones. + /// `skipMissingInputs` can be changed to `true` to first check whether + /// the expected input paths exist and ignore the command if they don't. + /// Otherwise, `lipo` would fail if the given paths didn't exist. + static Future create( + Environment environment, + List darwinArchs, { + required String relativePath, + required String inputDir, + bool skipMissingInputs = false, + }) async { + + final String resultPath = environment.fileSystem.path.join(environment.buildDir.path, relativePath); + environment.fileSystem.directory(resultPath).parent.createSync(recursive: true); + + Iterable inputPaths = darwinArchs.map( + (DarwinArch iosArch) => environment.fileSystem.path.join(inputDir, getNameForDarwinArch(iosArch), relativePath) + ); + if (skipMissingInputs) { + inputPaths = inputPaths.where(environment.fileSystem.isFileSync); + if (inputPaths.isEmpty) { + return; + } + } + + final List lipoArgs = [ + 'lipo', + ...inputPaths, + '-create', + '-output', + resultPath, + ]; + + final ProcessResult result = await environment.processManager.run(lipoArgs); + if (result.exitCode != 0) { + throw Exception('lipo exited with code ${result.exitCode}.\n${result.stderr}'); + } + } +} diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 2eab6847a5f25..2bcb7668cd58f 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -112,19 +112,24 @@ abstract class AotAssemblyBase extends Target { if (results.any((int result) => result != 0)) { throw Exception('AOT snapshotter exited with code ${results.join()}'); } - final String resultPath = environment.fileSystem.path.join(environment.buildDir.path, 'App.framework', 'App'); - environment.fileSystem.directory(resultPath).parent.createSync(recursive: true); - final ProcessResult result = await environment.processManager.run([ - 'lipo', - ...darwinArchs.map((DarwinArch iosArch) => - environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')), - '-create', - '-output', - resultPath, - ]); - if (result.exitCode != 0) { - throw Exception('lipo exited with code ${result.exitCode}.\n${result.stderr}'); - } + + // Combine the app lib into a fat framework. + await Lipo.create( + environment, + darwinArchs, + relativePath: 'App.framework/App', + inputDir: buildOutputPath, + ); + + // And combine the dSYM for each architecture too, if it was created. + await Lipo.create( + environment, + darwinArchs, + relativePath: 'App.framework.dSYM/Contents/Resources/DWARF/App', + inputDir: buildOutputPath, + // Don't fail if the dSYM wasn't created (i.e. during a debug build). + skipMissingInputs: true, + ); } } @@ -489,6 +494,26 @@ abstract class IosAssetBundle extends Target { .copySync(frameworkBinaryPath); } + // Copy the dSYM + if (environment.buildDir.childDirectory('App.framework.dSYM').existsSync()) { + final File dsymOutputBinary = environment + .outputDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App'); + dsymOutputBinary.parent.createSync(recursive: true); + environment + .buildDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App') + .copySync(dsymOutputBinary.path); + } + // Copy the assets. final Depfile assetDepfile = await copyAssets( environment, @@ -547,8 +572,25 @@ class DebugIosApplicationBundle extends IosAssetBundle { ]; } +/// IosAssetBundle with debug symbols, used for Profile and Release builds. +abstract class _IosAssetBundleWithDSYM extends IosAssetBundle { + const _IosAssetBundleWithDSYM(); + + @override + List get inputs => [ + ...super.inputs, + const Source.pattern('{BUILD_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; + + @override + List get outputs => [ + ...super.outputs, + const Source.pattern('{OUTPUT_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; +} + /// Build a profile iOS application bundle. -class ProfileIosApplicationBundle extends IosAssetBundle { +class ProfileIosApplicationBundle extends _IosAssetBundleWithDSYM { const ProfileIosApplicationBundle(); @override @@ -561,7 +603,7 @@ class ProfileIosApplicationBundle extends IosAssetBundle { } /// Build a release iOS application bundle. -class ReleaseIosApplicationBundle extends IosAssetBundle { +class ReleaseIosApplicationBundle extends _IosAssetBundleWithDSYM { const ReleaseIosApplicationBundle(); @override diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index af08b070ea2f7..e88f883242d36 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -302,19 +302,23 @@ class CompileMacOSFramework extends Target { throw Exception('AOT snapshotter exited with code ${results.join()}'); } - final String resultPath = environment.fileSystem.path.join(environment.buildDir.path, 'App.framework', 'App'); - environment.fileSystem.directory(resultPath).parent.createSync(recursive: true); - final ProcessResult result = await environment.processManager.run([ - 'lipo', - ...darwinArchs.map((DarwinArch iosArch) => - environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')), - '-create', - '-output', - resultPath, - ]); - if (result.exitCode != 0) { - throw Exception('lipo exited with code ${result.exitCode}.\n${result.stderr}'); - } + // Combine the app lib into a fat framework. + await Lipo.create( + environment, + darwinArchs, + relativePath: 'App.framework/App', + inputDir: buildOutputPath, + ); + + // And combine the dSYM for each architecture too, if it was created. + await Lipo.create( + environment, + darwinArchs, + relativePath: 'App.framework.dSYM/Contents/Resources/DWARF/App', + inputDir: buildOutputPath, + // Don't fail if the dSYM wasn't created (i.e. during a debug build). + skipMissingInputs: true, + ); } @override @@ -332,6 +336,7 @@ class CompileMacOSFramework extends Target { @override List get outputs => const [ Source.pattern('{BUILD_DIR}/App.framework/App'), + Source.pattern('{BUILD_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), ]; } @@ -382,6 +387,26 @@ abstract class MacOSBundleFlutterAssets extends Target { .childFile('App') .copySync(outputDirectory.childFile('App').path); + // Copy the dSYM + if (environment.buildDir.childDirectory('App.framework.dSYM').existsSync()) { + final File dsymOutputBinary = environment + .outputDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App'); + dsymOutputBinary.parent.createSync(recursive: true); + environment + .buildDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App') + .copySync(dsymOutputBinary.path); + } + // Copy assets into asset directory. final Directory assetDirectory = outputDirectory .childDirectory('Resources') @@ -530,6 +555,18 @@ class ProfileMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { CompileMacOSFramework(), ProfileUnpackMacOS(), ]; + + @override + List get inputs => [ + ...super.inputs, + const Source.pattern('{BUILD_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; + + @override + List get outputs => [ + ...super.outputs, + const Source.pattern('{OUTPUT_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; } @@ -546,6 +583,18 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { ReleaseUnpackMacOS(), ]; + @override + List get inputs => [ + ...super.inputs, + const Source.pattern('{BUILD_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; + + @override + List get outputs => [ + ...super.outputs, + const Source.pattern('{OUTPUT_DIR}/App.framework.dSYM/Contents/Resources/DWARF/App'), + ]; + @override Future build(Environment environment) async { bool buildSuccess = true; diff --git a/packages/flutter_tools/lib/src/bundle_builder.dart b/packages/flutter_tools/lib/src/bundle_builder.dart index 402b8455160d0..f41c682cb2082 100644 --- a/packages/flutter_tools/lib/src/bundle_builder.dart +++ b/packages/flutter_tools/lib/src/bundle_builder.dart @@ -166,7 +166,7 @@ Future writeBundle( try { // This will result in strange looking files, for example files with `/` // on Windows or files that end up getting URI encoded such as `#.ext` - // to `%23.ext`. However, we have to keep it this way since the + // to `%23.ext`. However, we have to keep it this way since the // platform channels in the framework will URI encode these values, // and the native APIs will look for files this way. final File file = globals.fs.file(globals.fs.path.join(bundleDir.path, entry.key)); diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index e63d2a42793b1..fde75ada7091a 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -112,6 +113,9 @@ class AnalyzeCommand extends FlutterCommand { @override String get category => FlutterCommandCategory.project; + @visibleForTesting + List allProjectValidators() => _allProjectValidators; + @override bool get shouldRunPub { // If they're not analyzing the current project. diff --git a/packages/flutter_tools/lib/src/commands/analyze_base.dart b/packages/flutter_tools/lib/src/commands/analyze_base.dart index 54a9ff6fe0582..cdd21a7659b3a 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_base.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_base.dart @@ -87,7 +87,7 @@ abstract class AnalyzeBase { return artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path; } bool get isBenchmarking => argResults['benchmark'] as bool; - String get protocolTrafficLog => argResults['protocol-traffic-log'] as String; + String? get protocolTrafficLog => argResults['protocol-traffic-log'] as String?; /// Generate an analysis summary for both [AnalyzeOnce], [AnalyzeContinuously]. static String generateErrorsMessage({ diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index 9ec39afaf8d4c..75b11e80b335a 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -422,7 +422,7 @@ end kTargetFile: targetFile, kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios), kBitcodeFlag: 'true', - kIosArchs: defaultIOSArchsForEnvironment(sdkType) + kIosArchs: defaultIOSArchsForEnvironment(sdkType, globals.artifacts!) .map(getNameForDarwinArch) .join(' '), kSdkRoot: await globals.xcode!.sdkLocation(sdkType), diff --git a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart index 60d32b85da864..e6e65f4b3185e 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart @@ -193,10 +193,9 @@ end defines: { kTargetFile: targetFile, kTargetPlatform: getNameForTargetPlatform(TargetPlatform.darwin), - kDarwinArchs: [ - DarwinArch.x86_64, - DarwinArch.arm64, - ].map(getNameForDarwinArch).join(' '), + kDarwinArchs: defaultMacOSArchsForEnvironment(globals.artifacts!) + .map(getNameForDarwinArch) + .join(' '), ...buildInfo.toBuildSystemEnvironment(), }, artifacts: globals.artifacts!, diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 0923d70c3bc0b..b999ea482bd72 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -644,7 +644,7 @@ Your $application code is in $relativeAppMain. } // Takes an application template and replaces the main.dart with one from the - // documentation website in sampleCode. Returns the difference in the number + // documentation website in sampleCode. Returns the difference in the number // of files after applying the sample, since it also deletes the application's // test directory (since the template's test doesn't apply to the sample). int _applySample(Directory directory, String sampleCode) { diff --git a/packages/flutter_tools/lib/src/commands/custom_devices.dart b/packages/flutter_tools/lib/src/commands/custom_devices.dart index 79b7b6778984e..96ff6e8054866 100644 --- a/packages/flutter_tools/lib/src/commands/custom_devices.dart +++ b/packages/flutter_tools/lib/src/commands/custom_devices.dart @@ -598,39 +598,39 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { inputs = StreamQueue(nonClosingKeystrokes.stream); - final String id = await (askForString( + final String id = (await askForString( 'id', description: 'Please enter the id you want to device to have. Must contain only ' 'alphanumeric or underscore characters.', example: 'pi', validator: (String s) async => RegExp(r'^\w+$').hasMatch(s), - ) as FutureOr); + ))!; - final String label = await (askForString( + final String label = (await askForString( 'label', description: 'Please enter the label of the device, which is a slightly more verbose ' 'name for the device.', example: 'Raspberry Pi', - ) as FutureOr); + ))!; - final String sdkNameAndVersion = await (askForString( + final String sdkNameAndVersion = (await askForString( 'SDK name and version', example: 'Raspberry Pi 4 Model B+', - ) as FutureOr); + ))!; final bool enabled = await askForBool( 'enabled', description: 'Should the device be enabled?', ); - final String targetStr = await (askForString( + final String targetStr = (await askForString( 'target', description: 'Please enter the hostname or IPv4/v6 address of the device.', example: 'raspberrypi', validator: (String s) async => _isValidHostname(s) || _isValidIpAddr(s) - ) as FutureOr); + ))!; final InternetAddress? targetIp = InternetAddress.tryParse(targetStr); final bool useIp = targetIp != null; @@ -639,20 +639,20 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4; - final String username = await (askForString( + final String username = (await askForString( 'username', description: 'Please enter the username used for ssh-ing into the remote device.', example: 'pi', defaultsTo: 'no username', - ) as FutureOr); + ))!; - final String remoteRunDebugCommand = await (askForString( + final String remoteRunDebugCommand = (await askForString( 'run command', description: 'Please enter the command executed on the remote device for starting ' r'the app. "/tmp/${appName}" is the path to the asset bundle.', example: r'flutter-pi /tmp/${appName}' - ) as FutureOr); + ))!; final bool usePortForwarding = await askForBool( 'use port forwarding', @@ -663,12 +663,12 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { 'not using port forwarding.', ); - final String screenshotCommand = await (askForString( + final String screenshotCommand = (await askForString( 'screenshot command', description: 'Enter the command executed on the remote device for taking a screenshot.', example: r"fbgrab /tmp/screenshot.png && cat /tmp/screenshot.png | base64 | tr -d ' \n\t'", defaultsTo: 'no screenshotting support', - ) as FutureOr); + ))!; // SSH expects IPv6 addresses to use the bracket syntax like URIs do too, // but the IPv6 the user enters is a raw IPv6 address, so we need to wrap it. @@ -820,8 +820,8 @@ Delete a device from the config file. Future runCommand() async { checkFeatureEnabled(); - final String id = globalResults!['device-id'] as String; - if (!customDevicesConfig.contains(id)) { + final String? id = globalResults!['device-id'] as String?; + if (id == null || !customDevicesConfig.contains(id)) { throwToolExit('Couldn\'t find device with id "$id" in config at "${customDevicesConfig.configPath}"'); } diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 193426213bd29..5b1d8f4ebdd94 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -123,7 +123,7 @@ class _DaemonServer { // We have to listen to socket.done. Otherwise when the connection is // reset, we will receive an uncatchable exception. // https://github.com/dart-lang/sdk/issues/25518 - final Future socketDone = socket.done.catchError((dynamic error, StackTrace stackTrace) { + final Future socketDone = socket.done.catchError((Object error, StackTrace stackTrace) { logger!.printError('Socket error: $error'); logger!.printTrace('$stackTrace'); }); @@ -145,8 +145,8 @@ class _DaemonServer { } } -typedef CommandHandler = Future? Function(Map args); -typedef CommandHandlerWithBinary = Future Function(Map args, Stream>? binary); +typedef CommandHandler = Future? Function(Map args); +typedef CommandHandlerWithBinary = Future Function(Map args, Stream>? binary); class Daemon { Daemon( @@ -221,7 +221,7 @@ class Daemon { throw DaemonException('no domain for method: $method'); } - _domainMap[prefix]!.handleCommand(name, id, castStringKeyedMap(request.data['params']) ?? const {}, request.binary); + _domainMap[prefix]!.handleCommand(name, id, castStringKeyedMap(request.data['params']) ?? const {}, request.binary); } on Exception catch (error, trace) { connection.sendErrorResponse(id, _toJsonable(error), trace); } @@ -268,52 +268,53 @@ abstract class Domain { @override String toString() => name; - void handleCommand(String command, Object id, Map args, Stream>? binary) { - Future.sync(() { + void handleCommand(String command, Object id, Map args, Stream>? binary) { + Future.sync(() { if (_handlers.containsKey(command)) { return _handlers[command]!(args); } else if (_handlersWithBinary.containsKey(command)) { return _handlersWithBinary[command]!(args, binary); } throw DaemonException('command not understood: $name.$command'); - }).then((dynamic result) { + }).then((Object? result) { daemon.connection.sendResponse(id, _toJsonable(result)); + return null; }).catchError((Object error, StackTrace stackTrace) { daemon.connection.sendErrorResponse(id, _toJsonable(error), stackTrace); }); } - void sendEvent(String name, [ dynamic args, List? binary ]) { + void sendEvent(String name, [ Object? args, List? binary ]) { daemon.connection.sendEvent(name, _toJsonable(args), binary); } - String? _getStringArg(Map args, String name, { bool required = false }) { + String? _getStringArg(Map args, String name, { bool required = false }) { if (required && !args.containsKey(name)) { throw DaemonException('$name is required'); } - final dynamic val = args[name]; + final Object? val = args[name]; if (val != null && val is! String) { throw DaemonException('$name is not a String'); } return val as String?; } - bool? _getBoolArg(Map args, String name, { bool required = false }) { + bool? _getBoolArg(Map args, String name, { bool required = false }) { if (required && !args.containsKey(name)) { throw DaemonException('$name is required'); } - final dynamic val = args[name]; + final Object? val = args[name]; if (val != null && val is! bool) { throw DaemonException('$name is not a bool'); } return val as bool?; } - int? _getIntArg(Map args, String name, { bool required = false }) { + int? _getIntArg(Map args, String name, { bool required = false }) { if (required && !args.containsKey(name)) { throw DaemonException('$name is required'); } - final dynamic val = args[name]; + final Object? val = args[name]; if (val != null && val is! int) { throw DaemonException('$name is not an int'); } @@ -334,7 +335,7 @@ class DaemonDomain extends Domain { sendEvent( 'daemon.connected', - { + { 'version': protocolVersion, 'pid': pid, }, @@ -357,13 +358,13 @@ class DaemonDomain extends Domain { } } else { if (message.stackTrace != null) { - sendEvent('daemon.logMessage', { + sendEvent('daemon.logMessage', { 'level': message.level, 'message': message.message, 'stackTrace': message.stackTrace.toString(), }); } else { - sendEvent('daemon.logMessage', { + sendEvent('daemon.logMessage', { 'level': message.level, 'message': message.message, }); @@ -374,7 +375,7 @@ class DaemonDomain extends Domain { StreamSubscription? _subscription; - Future version(Map args) { + Future version(Map args) { return Future.value(protocolVersion); } @@ -384,16 +385,16 @@ class DaemonDomain extends Domain { /// --web-allow-expose-url switch. The client may return the same URL back if /// tunnelling is not required for a given URL. Future exposeUrl(String url) async { - final dynamic res = await daemon.connection.sendRequest('app.exposeUrl', {'url': url}); - if (res is Map && res['url'] is String) { - return res['url'] as String; + final Object? res = await daemon.connection.sendRequest('app.exposeUrl', {'url': url}); + if (res is Map && res['url'] is String) { + return res['url']! as String; } else { globals.printError('Invalid response to exposeUrl - params should include a String url field'); return url; } } - Future shutdown(Map args) { + Future shutdown(Map args) { Timer.run(daemon.shutdown); return Future.value(); } @@ -408,7 +409,7 @@ class DaemonDomain extends Domain { /// This does not filter based on the current workflow restrictions, such /// as whether command line tools are installed or whether the host platform /// is correct. - Future> getSupportedPlatforms(Map args) async { + Future> getSupportedPlatforms(Map args) async { final String? projectRoot = _getStringArg(args, 'projectRoot', required: true); final List result = []; try { @@ -442,7 +443,7 @@ class DaemonDomain extends Domain { 'platforms': result, }; } on Exception catch (err, stackTrace) { - sendEvent('log', { + sendEvent('log', { 'log': 'Failed to parse project metadata', 'stackTrace': stackTrace.toString(), 'error': true, @@ -604,7 +605,7 @@ class AppDomain extends Domain { logger.domain = this; logger.app = app; - _sendAppEvent(app, 'start', { + _sendAppEvent(app, 'start', { 'deviceId': device.id, 'directory': projectDirectory, 'supportsRestart': isRestartSupported(enableHotReload, device), @@ -619,7 +620,7 @@ class AppDomain extends Domain { // As it just writes to stdout. unawaited(connectionInfoCompleter.future.then( (DebugConnectionInfo info) { - final Map params = { + final Map params = { // The web vmservice proxy does not have an http address. 'port': info.httpUri?.port ?? info.wsUri!.port, 'wsUri': info.wsUri.toString(), @@ -646,7 +647,7 @@ class AppDomain extends Domain { ); _sendAppEvent(app, 'stop'); } on Exception catch (error, trace) { - _sendAppEvent(app, 'stop', { + _sendAppEvent(app, 'stop', { 'error': _toJsonable(error), 'trace': '$trace', }); @@ -665,7 +666,7 @@ class AppDomain extends Domain { final int _hotReloadDebounceDurationMs = 50; - Future? restart(Map args) async { + Future? restart(Map args) async { final String? appId = _getStringArg(args, 'appId', required: true); final bool fullRestart = _getBoolArg(args, 'fullRestart') ?? false; final bool pauseAfterRestart = _getBoolArg(args, 'pause') ?? false; @@ -727,18 +728,18 @@ class AppDomain extends Domain { /// "type":"_extensionType", /// "method":"ext.flutter.platformOverride" /// } - Future> callServiceExtension(Map args) async { + Future> callServiceExtension(Map args) async { final String? appId = _getStringArg(args, 'appId', required: true); final String methodName = _getStringArg(args, 'methodName')!; - final Map? params = args['params'] == null ? {} : castStringKeyedMap(args['params']); + final Map? params = args['params'] == null ? {} : castStringKeyedMap(args['params']); final AppInstance? app = _getApp(appId); if (app == null) { throw DaemonException("app '$appId' not found"); } - final FlutterDevice device = app.runner!.flutterDevices.first!; + final FlutterDevice device = app.runner!.flutterDevices.first; final List views = await device.vmService!.getFlutterViews(); - final Map? result = await device + final Map? result = await device .vmService! .invokeFlutterExtensionRpcRaw( methodName, @@ -752,13 +753,13 @@ class AppDomain extends Domain { if (result.containsKey('error')) { // ignore: only_throw_errors - throw result['error']! as Object; + throw result['error']!; } return result; } - Future stop(Map args) async { + Future stop(Map args) async { final String? appId = _getStringArg(args, 'appId', required: true); final AppInstance? app = _getApp(appId); @@ -768,8 +769,8 @@ class AppDomain extends Domain { return app.stop().then( (void value) => true, - onError: (dynamic error, StackTrace stack) { - _sendAppEvent(app, 'log', {'log': '$error', 'error': true}); + onError: (Object? error, StackTrace stack) { + _sendAppEvent(app, 'log', {'log': '$error', 'error': true}); app.closeLogger(); _apps.remove(app); return false; @@ -777,7 +778,7 @@ class AppDomain extends Domain { ); } - Future detach(Map args) async { + Future detach(Map args) async { final String? appId = _getStringArg(args, 'appId', required: true); final AppInstance? app = _getApp(appId); @@ -787,8 +788,8 @@ class AppDomain extends Domain { return app.detach().then( (void value) => true, - onError: (dynamic error, StackTrace stack) { - _sendAppEvent(app, 'log', {'log': '$error', 'error': true}); + onError: (Object? error, StackTrace stack) { + _sendAppEvent(app, 'log', {'log': '$error', 'error': true}); app.closeLogger(); _apps.remove(app); return false; @@ -805,8 +806,8 @@ class AppDomain extends Domain { return null; } - void _sendAppEvent(AppInstance app, String name, [ Map? args ]) { - sendEvent('app.$name', { + void _sendAppEvent(AppInstance app, String name, [ Map? args ]) { + sendEvent('app.$name', { 'appId': app.id, ...?args, }); @@ -876,8 +877,8 @@ class DeviceDomain extends Domain { /// Return a list of the current devices, with each device represented as a map /// of properties (id, name, platform, ...). - Future>> getDevices([ Map? args ]) async { - return >[ + Future>> getDevices([ Map? args ]) async { + return >[ for (final PollingDeviceDiscovery discoverer in _discoverers) for (final Device device in await discoverer.devices) await _deviceToMap(device), @@ -885,8 +886,8 @@ class DeviceDomain extends Domain { } /// Return a list of the current devices, discarding existing cache of devices. - Future>> discoverDevices([ Map? args ]) async { - return >[ + Future>> discoverDevices([ Map? args ]) async { + return >[ for (final PollingDeviceDiscovery discoverer in _discoverers) for (final Device device in await discoverer.discoverDevices()) await _deviceToMap(device), @@ -894,21 +895,21 @@ class DeviceDomain extends Domain { } /// Enable device events. - Future enable(Map args) async { + Future enable(Map args) async { for (final PollingDeviceDiscovery discoverer in _discoverers) { discoverer.startPolling(); } } /// Disable device events. - Future disable(Map args) async { + Future disable(Map args) async { for (final PollingDeviceDiscovery discoverer in _discoverers) { discoverer.stopPolling(); } } /// Forward a host port to a device port. - Future> forward(Map args) async { + Future> forward(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final int devicePort = _getIntArg(args, 'devicePort', required: true)!; int? hostPort = _getIntArg(args, 'hostPort'); @@ -920,11 +921,11 @@ class DeviceDomain extends Domain { hostPort = await device.portForwarder!.forward(devicePort, hostPort: hostPort); - return {'hostPort': hostPort}; + return {'hostPort': hostPort}; } /// Removes a forwarded port. - Future unforward(Map args) async { + Future unforward(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final int devicePort = _getIntArg(args, 'devicePort', required: true)!; final int hostPort = _getIntArg(args, 'hostPort', required: true)!; @@ -938,7 +939,7 @@ class DeviceDomain extends Domain { } /// Returns whether a device supports runtime mode. - Future supportsRuntimeMode(Map args) async { + Future supportsRuntimeMode(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final Device? device = await daemon.deviceDomain._getDevice(deviceId); if (device == null) { @@ -949,7 +950,7 @@ class DeviceDomain extends Domain { } /// Creates an application package from a file in the temp directory. - Future uploadApplicationPackage(Map args) async { + Future uploadApplicationPackage(Map args) async { final TargetPlatform targetPlatform = getTargetPlatformForName(_getStringArg(args, 'targetPlatform', required: true)!); final File applicationBinary = daemon.proxyDomain.tempDirectory.childFile(_getStringArg(args, 'applicationBinary', required: true)!); final ApplicationPackage? applicationPackage = await ApplicationPackageFactory.instance!.getPackageForPlatform( @@ -962,7 +963,7 @@ class DeviceDomain extends Domain { } /// Starts the log reader on the device. - Future startLogReader(Map args) async { + Future startLogReader(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final Device? device = await daemon.deviceDomain._getDevice(deviceId); if (device == null) { @@ -981,13 +982,13 @@ class DeviceDomain extends Domain { } /// Stops a log reader that was previously started. - Future stopLogReader(Map args) async { + Future stopLogReader(Map args) async { final String? id = _getStringArg(args, 'id', required: true); _logReaders.remove(id)?.dispose(); } /// Starts an app on a device. - Future> startApp(Map args) async { + Future> startApp(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final Device? device = await daemon.deviceDomain._getDevice(deviceId); if (device == null) { @@ -1010,14 +1011,14 @@ class DeviceDomain extends Domain { ipv6: _getBoolArg(args, 'ipv6') ?? false, userIdentifier: _getStringArg(args, 'userIdentifier'), ); - return { + return { 'started': result.started, 'observatoryUri': result.observatoryUri?.toString(), }; } /// Stops an app. - Future stopApp(Map args) async { + Future stopApp(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final Device? device = await daemon.deviceDomain._getDevice(deviceId); if (device == null) { @@ -1032,7 +1033,7 @@ class DeviceDomain extends Domain { } /// Takes a screenshot. - Future takeScreenshot(Map args) async { + Future takeScreenshot(Map args) async { final String? deviceId = _getStringArg(args, 'deviceId', required: true); final Device? device = await daemon.deviceDomain._getDevice(deviceId); if (device == null) { @@ -1082,10 +1083,10 @@ class DevToolsDomain extends Domain { DevtoolsLauncher? _devtoolsLauncher; - Future> serve([ Map? args ]) async { + Future> serve([ Map? args ]) async { _devtoolsLauncher ??= DevtoolsLauncher.instance; final DevToolsServerAddress? server = await _devtoolsLauncher?.serve(); - return{ + return{ 'host': server?.host, 'port': server?.port, }; @@ -1097,8 +1098,8 @@ class DevToolsDomain extends Domain { } } -Future> _deviceToMap(Device device) async { - return { +Future> _deviceToMap(Device device) async { + return { 'id': device.id, 'name': device.name, 'platform': getNameForTargetPlatform(await device.targetPlatform), @@ -1120,8 +1121,8 @@ Future> _deviceToMap(Device device) async { }; } -Map _emulatorToMap(Emulator emulator) { - return { +Map _emulatorToMap(Emulator emulator) { + return { 'id': emulator.id, 'name': emulator.name, 'category': emulator.category.toString(), @@ -1129,15 +1130,15 @@ Map _emulatorToMap(Emulator emulator) { }; } -Map _operationResultToMap(OperationResult result) { - return { +Map _operationResultToMap(OperationResult result) { + return { 'code': result.code, 'message': result.message, }; } -Object? _toJsonable(dynamic obj) { - if (obj is String || obj is int || obj is bool || obj is Map || obj is List || obj == null) { +Object? _toJsonable(Object? obj) { + if (obj is String || obj is int || obj is bool || obj is Map || obj is List || obj == null) { return obj; } if (obj is OperationResult) { @@ -1250,7 +1251,7 @@ class NotifyingLogger extends DelegatingLogger { } @override - void sendEvent(String name, [Map? args]) { } + void sendEvent(String name, [Map? args]) { } @override bool get supportsColor => throw UnimplementedError(); @@ -1305,12 +1306,12 @@ class EmulatorDomain extends Domain { androidWorkflow: androidWorkflow!, ); - Future>> getEmulators([ Map? args ]) async { + Future>> getEmulators([ Map? args ]) async { final List list = await emulators.getAllAvailableEmulators(); - return list.map>(_emulatorToMap).toList(); + return list.map>(_emulatorToMap).toList(); } - Future launch(Map args) async { + Future launch(Map args) async { final String emulatorId = _getStringArg(args, 'emulatorId', required: true)!; final bool coldBoot = _getBoolArg(args, 'coldBoot') ?? false; final List matches = @@ -1324,10 +1325,10 @@ class EmulatorDomain extends Domain { } } - Future> create(Map args) async { + Future> create(Map args) async { final String? name = _getStringArg(args, 'name'); final CreateEmulatorResult res = await emulators.createEmulator(name: name); - return { + return { 'success': res.success, 'emulatorName': res.emulatorName, 'error': res.error, @@ -1349,7 +1350,7 @@ class ProxyDomain extends Domain { int _id = 0; /// Writes to a file in a local temporary directory. - Future writeTempFile(Map args, Stream>? binary) async { + Future writeTempFile(Map args, Stream>? binary) async { final String path = _getStringArg(args, 'path', required: true)!; final File file = tempDirectory.childFile(path); await file.parent.create(recursive: true); @@ -1357,7 +1358,7 @@ class ProxyDomain extends Domain { } /// Calculate rolling hashes for a file in the local temporary directory. - Future?> calculateFileHashes(Map args) async { + Future?> calculateFileHashes(Map args) async { final String path = _getStringArg(args, 'path', required: true)!; final File file = tempDirectory.childFile(path); if (!await file.exists()) { @@ -1367,20 +1368,20 @@ class ProxyDomain extends Domain { return result.toJson(); } - Future updateFile(Map args, Stream>? binary) async { + Future updateFile(Map args, Stream>? binary) async { final String path = _getStringArg(args, 'path', required: true)!; final File file = tempDirectory.childFile(path); if (!await file.exists()) { return null; } - final List> deltaJson = (args['delta'] as List).cast>(); + final List> deltaJson = (args['delta']! as List).cast>(); final List delta = FileDeltaBlock.fromJsonList(deltaJson); final bool result = await FileTransfer().rebuildFile(file, delta, binary!); return result; } /// Opens a connection to a local port, and returns the connection id. - Future connect(Map args) async { + Future connect(Map args) async { final int targetPort = _getIntArg(args, 'port', required: true)!; final String id = 'portForwarder_${targetPort}_${_id++}'; @@ -1406,22 +1407,22 @@ class ProxyDomain extends Domain { _forwardedConnections[id] = socket; socket.listen((List data) { sendEvent('proxy.data.$id', null, data); - }, onError: (dynamic error, StackTrace stackTrace) { + }, onError: (Object error, StackTrace stackTrace) { // Socket error, probably disconnected. globals.logger.printTrace('Socket error: $error, $stackTrace'); }); - unawaited(socket.done.catchError((dynamic error, StackTrace stackTrace) { + unawaited(socket.done.catchError((Object error, StackTrace stackTrace) { // Socket error, probably disconnected. globals.logger.printTrace('Socket error: $error, $stackTrace'); - }).then((dynamic _) { + }).then((Object? _) { sendEvent('proxy.disconnected.$id'); })); return id; } /// Disconnects from a previously established connection. - Future disconnect(Map args) async { + Future disconnect(Map args) async { final String? id = _getStringArg(args, 'id', required: true); if (_forwardedConnections.containsKey(id)) { await _forwardedConnections.remove(id)?.close(); @@ -1431,7 +1432,7 @@ class ProxyDomain extends Domain { } /// Writes to a previously established connection. - Future write(Map args, Stream>? binary) async { + Future write(Map args, Stream>? binary) async { final String? id = _getStringArg(args, 'id', required: true); if (_forwardedConnections.containsKey(id)) { final StreamSubscription> subscription = binary!.listen(_forwardedConnections[id!]!.add); @@ -1519,7 +1520,7 @@ class AppRunLogger extends DelegatingLogger { printStatus(message); } } else { - final Map event = { + final Map event = { 'id': eventId, 'progressId': eventType, if (message != null) 'message': message, @@ -1531,7 +1532,7 @@ class AppRunLogger extends DelegatingLogger { } @override - void sendEvent(String name, [Map? args, List? binary]) { + void sendEvent(String name, [Map? args, List? binary]) { if (domain == null) { printStatus('event sent after app closed: $name'); } else { @@ -1589,7 +1590,7 @@ class DebounceOperationQueue { final Map> _operationQueue = >{}; Future? _inProgressAction; - Future? queueAndDebounce( + Future queueAndDebounce( K operationType, Duration debounceDuration, Future Function() action, @@ -1598,7 +1599,7 @@ class DebounceOperationQueue { // debounce timer and return its future. if (_operationQueue[operationType] != null) { _debounceTimers[operationType]?.reset(); - return _operationQueue[operationType]; + return _operationQueue[operationType]!; } // Otherwise, put one in the queue with a timer. diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index 3e4ca94fe2f8b..d84f0ca15e292 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - - import 'dart:async'; import 'package:meta/meta.dart'; diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index 74a6678a0140e..f7e320b85708e 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -2,8 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:process/process.dart'; + +import '../artifacts.dart'; import '../base/common.dart'; import '../base/file_system.dart'; +import '../base/io.dart'; import '../base/logger.dart'; import '../globals.dart' as globals; import '../localizations/gen_l10n.dart'; @@ -21,9 +25,13 @@ class GenerateLocalizationsCommand extends FlutterCommand { GenerateLocalizationsCommand({ required FileSystem fileSystem, required Logger logger, + required Artifacts artifacts, + required ProcessManager processManager, }) : _fileSystem = fileSystem, - _logger = logger { + _logger = logger, + _artifacts = artifacts, + _processManager = processManager { argParser.addOption( 'arb-dir', defaultsTo: globals.fs.path.join('lib', 'l10n'), @@ -180,10 +188,16 @@ class GenerateLocalizationsCommand extends FlutterCommand { 'Localizations.of(context), removing the need for null checking in ' 'user code.' ); + argParser.addFlag( + 'format', + help: 'When specified, the "dart format" command is run after generating the localization files.' + ); } final FileSystem _fileSystem; final Logger _logger; + final Artifacts _artifacts; + final ProcessManager _processManager; @override String get description => 'Generate localizations for the current project.'; @@ -196,6 +210,10 @@ class GenerateLocalizationsCommand extends FlutterCommand { @override Future runCommand() async { + List outputFileList; + + bool format = boolArg('format') ?? false; + if (_fileSystem.file('l10n.yaml').existsSync()) { final LocalizationOptions options = parseLocalizationsOptions( file: _fileSystem.file('l10n.yaml'), @@ -207,57 +225,71 @@ class GenerateLocalizationsCommand extends FlutterCommand { 'To use the command line arguments, delete the l10n.yaml file in the ' 'Flutter project.\n\n' ); - generateLocalizations( + outputFileList = generateLocalizations( logger: _logger, options: options, projectDir: _fileSystem.currentDirectory, fileSystem: _fileSystem, - ); - return FlutterCommandResult.success(); - } + ).outputFileList; + format = format || options.format; + } else { + final String inputPathString = stringArgDeprecated('arb-dir')!; // Has default value, cannot be null. + final String? outputPathString = stringArgDeprecated('output-dir'); + final String outputFileString = stringArgDeprecated('output-localization-file')!; // Has default value, cannot be null. + final String templateArbFileName = stringArgDeprecated('template-arb-file')!; // Has default value, cannot be null. + final String? untranslatedMessagesFile = stringArgDeprecated('untranslated-messages-file'); + final String classNameString = stringArgDeprecated('output-class')!; // Has default value, cannot be null. + final List preferredSupportedLocales = stringsArg('preferred-supported-locales'); + final String? headerString = stringArgDeprecated('header'); + final String? headerFile = stringArgDeprecated('header-file'); + final bool useDeferredLoading = boolArgDeprecated('use-deferred-loading'); + final String? inputsAndOutputsListPath = stringArgDeprecated('gen-inputs-and-outputs-list'); + final bool useSyntheticPackage = boolArgDeprecated('synthetic-package'); + final String? projectPathString = stringArgDeprecated('project-dir'); + final bool areResourceAttributesRequired = boolArgDeprecated('required-resource-attributes'); + final bool usesNullableGetter = boolArgDeprecated('nullable-getter'); - final String inputPathString = stringArgDeprecated('arb-dir')!; // Has default value, cannot be null. - final String? outputPathString = stringArgDeprecated('output-dir'); - final String outputFileString = stringArgDeprecated('output-localization-file')!; // Has default value, cannot be null. - final String templateArbFileName = stringArgDeprecated('template-arb-file')!; // Has default value, cannot be null. - final String? untranslatedMessagesFile = stringArgDeprecated('untranslated-messages-file'); - final String classNameString = stringArgDeprecated('output-class')!; // Has default value, cannot be null. - final List preferredSupportedLocales = stringsArg('preferred-supported-locales'); - final String? headerString = stringArgDeprecated('header'); - final String? headerFile = stringArgDeprecated('header-file'); - final bool useDeferredLoading = boolArgDeprecated('use-deferred-loading'); - final String? inputsAndOutputsListPath = stringArgDeprecated('gen-inputs-and-outputs-list'); - final bool useSyntheticPackage = boolArgDeprecated('synthetic-package'); - final String? projectPathString = stringArgDeprecated('project-dir'); - final bool areResourceAttributesRequired = boolArgDeprecated('required-resource-attributes'); - final bool usesNullableGetter = boolArgDeprecated('nullable-getter'); + precacheLanguageAndRegionTags(); - precacheLanguageAndRegionTags(); + try { + outputFileList = (LocalizationsGenerator( + fileSystem: _fileSystem, + inputPathString: inputPathString, + outputPathString: outputPathString, + templateArbFileName: templateArbFileName, + outputFileString: outputFileString, + classNameString: classNameString, + preferredSupportedLocales: preferredSupportedLocales, + headerString: headerString, + headerFile: headerFile, + useDeferredLoading: useDeferredLoading, + inputsAndOutputsListPath: inputsAndOutputsListPath, + useSyntheticPackage: useSyntheticPackage, + projectPathString: projectPathString, + areResourceAttributesRequired: areResourceAttributesRequired, + untranslatedMessagesFile: untranslatedMessagesFile, + usesNullableGetter: usesNullableGetter, + logger: _logger, + ) + ..loadResources() + ..writeOutputFiles()) + .outputFileList; + } on L10nException catch (e) { + throwToolExit(e.message); + } + } - try { - LocalizationsGenerator( - fileSystem: _fileSystem, - inputPathString: inputPathString, - outputPathString: outputPathString, - templateArbFileName: templateArbFileName, - outputFileString: outputFileString, - classNameString: classNameString, - preferredSupportedLocales: preferredSupportedLocales, - headerString: headerString, - headerFile: headerFile, - useDeferredLoading: useDeferredLoading, - inputsAndOutputsListPath: inputsAndOutputsListPath, - useSyntheticPackage: useSyntheticPackage, - projectPathString: projectPathString, - areResourceAttributesRequired: areResourceAttributesRequired, - untranslatedMessagesFile: untranslatedMessagesFile, - usesNullableGetter: usesNullableGetter, - logger: _logger, - ) - ..loadResources() - ..writeOutputFiles(); - } on L10nException catch (e) { - throwToolExit(e.message); + // All other post processing. + if (format) { + if (outputFileList.isEmpty) { + return FlutterCommandResult.success(); + } + final String dartBinary = _artifacts.getHostArtifact(HostArtifact.engineDartBinary).path; + final List command = [dartBinary, 'format', ...outputFileList]; + final ProcessResult result = await _processManager.run(command); + if (result.exitCode != 0) { + throwToolExit('Formatting failed: $result', exitCode: result.exitCode); + } } return FlutterCommandResult.success(); diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 714a8b9c32fac..9cb22e3b01f22 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -512,7 +512,7 @@ class RunCommand extends RunCommandBase { } @visibleForTesting - Future createRunner({ + Future createRunner({ required bool hotMode, required List flutterDevices, required String? applicationBinaryPath, @@ -669,12 +669,12 @@ class RunCommand extends RunCommandBase { ), ]; - final ResidentRunner runner = await (createRunner( + final ResidentRunner runner = await createRunner( applicationBinaryPath: applicationBinaryPath, flutterDevices: flutterDevices, flutterProject: flutterProject, hotMode: hotMode, - ) as FutureOr); + ); DateTime? appStartedTime; // Sync completer so the completing agent attaching to the resident doesn't diff --git a/packages/flutter_tools/lib/src/commands/symbolize.dart b/packages/flutter_tools/lib/src/commands/symbolize.dart index a4edd6a25bc11..d8393f15d96a8 100644 --- a/packages/flutter_tools/lib/src/commands/symbolize.dart +++ b/packages/flutter_tools/lib/src/commands/symbolize.dart @@ -68,8 +68,11 @@ class SymbolizeCommand extends FlutterCommand { if (argResults?.wasParsed('debug-info') != true) { throwToolExit('"--debug-info" is required to symbolize stack traces.'); } - if (!_fileSystem.isFileSync(stringArgDeprecated('debug-info')!)) { - throwToolExit('${stringArgDeprecated('debug-info')} does not exist.'); + final String debugInfoPath = stringArgDeprecated('debug-info')!; + if (debugInfoPath.endsWith('.dSYM') + ? !_fileSystem.isDirectorySync(debugInfoPath) + : !_fileSystem.isFileSync(debugInfoPath)) { + throwToolExit('$debugInfoPath does not exist.'); } if ((argResults?.wasParsed('input') ?? false) && !_fileSystem.isFileSync(stringArgDeprecated('input')!)) { throwToolExit('${stringArgDeprecated('input')} does not exist.'); @@ -105,7 +108,25 @@ class SymbolizeCommand extends FlutterCommand { input = _stdio.stdin; } - final Uint8List symbols = _fileSystem.file(stringArgDeprecated('debug-info')).readAsBytesSync(); + String debugInfoPath = stringArgDeprecated('debug-info')!; + + // If it's a dSYM container, expand the path to the actual DWARF. + if (debugInfoPath.endsWith('.dSYM')) { + final Directory debugInfoDir = _fileSystem + .directory(debugInfoPath) + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF'); + + final List dwarfFiles = debugInfoDir.listSync().whereType().toList(); + if (dwarfFiles.length == 1) { + debugInfoPath = dwarfFiles.first.path; + } else { + throwToolExit('Expected a single DWARF file in a dSYM container.'); + } + } + + final Uint8List symbols = _fileSystem.file(debugInfoPath).readAsBytesSync(); await _dwarfSymbolizationService.decode( input: input, output: output, diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 0974778be64f2..dbef897c9718e 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -31,8 +31,6 @@ const Map kManuallyPinnedDependencies = { 'flutter_gallery_assets': '1.0.2', // Tests depend on the exact version. 'flutter_template_images': '4.2.0', // Must always exactly match flutter_tools template. 'video_player': '2.2.11', - // A gradle upgrade upstream causes a devicelab test to fail: https://github.com/flutter/flutter/issues/109397 - 'path_provider_android': '2.0.17', // Could potentially break color scheme tests on upgrade, // so pin and manually update as needed. 'material_color_utilities': '0.2.0', diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index d419b88a7d38b..5483ee1e83b76 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -753,10 +753,6 @@ class DefaultResidentCompiler implements ResidentCompiler { if (testCompilation) '--no-print-incremental-dependencies', '--target=$targetModel', - // TODO(zanderso): remove once this becomes the default behavior - // in the frontend_server. - // https://github.com/flutter/flutter/issues/52693 - '--debugger-module-names', // TODO(annagrin): remove once this becomes the default behavior // in the frontend_server. // https://github.com/flutter/flutter/issues/59902 diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index d35bdb5f3d148..ca5369c55d34a 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -313,7 +313,6 @@ Future runInContext( platform: globals.platform, usage: globals.flutterUsage, ), - ShutdownHooks: () => ShutdownHooks(logger: globals.logger), Stdio: () => Stdio(), SystemClock: () => const SystemClock(), Usage: () => Usage( diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index 5ea0d2c75d5e1..1f1f79af85fc8 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -59,11 +59,9 @@ class FlutterDebugAdapter extends DartDebugAdapter appStartedCompleter.isCompleted; - /// The VM Service URI received from the app.debugPort event. - Uri? _vmServiceUri; - /// The appId of the current running Flutter app. - String? _appId; + @visibleForTesting + String? appId; /// The ID to use for the next request sent to the Flutter run daemon. int _flutterRequestId = 1; @@ -311,13 +309,6 @@ class FlutterDebugAdapter extends DartDebugAdapter(>[ - sendFlutterRequest(method, {'appId': _appId}), - _process?.exitCode ?? Future.value(), - ]); + if (appId != null) { + final String method = isAttach ? 'app.detach' : 'app.stop'; + await Future.any(>[ + sendFlutterRequest(method, {'appId': appId}), + _process?.exitCode ?? Future.value(), + ]); + } terminatePids(ProcessSignal.sigterm); await _process?.exitCode; } /// Connects to the VM Service if the app.started event has fired, and a VM Service URI is available. - void _connectDebuggerIfReady() { - final Uri? serviceUri = _vmServiceUri; - - if (_receivedAppStarted && serviceUri != null) { + Future _connectDebugger(Uri vmServiceUri) async { if (enableDebugger) { - connectDebugger(serviceUri); + await connectDebugger(vmServiceUri); } else { // Usually, `connectDebugger` (in the base Dart adapter) will send this // event when it connects a debugger. Since we're not connecting a @@ -431,29 +421,30 @@ class FlutterDebugAdapter extends DartDebugAdapter{ - 'vmServiceUri': serviceUri.toString(), + 'vmServiceUri': vmServiceUri.toString(), }), eventType: 'dart.debuggerUris', ); } - } } /// Handles the app.start event from Flutter. void _handleAppStart(Map params) { - _appId = params['appId'] as String?; - assert(_appId != null); + appId = params['appId'] as String?; + if(appId == null) { + throw DebugAdapterException('Unexpected null `appId` in app.start event'); + } } /// Handles the app.started event from Flutter. - void _handleAppStarted() { + Future _handleAppStarted() async { appStartedCompleter.complete(); - _connectDebuggerIfReady(); // Send a custom event so the editor knows the app has started. // // This may be useful when there's no VM Service (for example Profile mode) // but the editor still wants to know that startup has finished. + await debuggerInitialized; // Ensure we're fully initialized before sending. sendEvent( RawEventBody({}), eventType: 'flutter.appStarted', @@ -472,13 +463,16 @@ class FlutterDebugAdapter extends DartDebugAdapter params) { + Future _handleDebugPort(Map params) async { // Capture the VM Service URL which we'll connect to when we get app.started. final String? wsUri = params['wsUri'] as String?; if (wsUri != null) { - _vmServiceUri = Uri.parse(wsUri); + final Uri vmServiceUri = Uri.parse(wsUri); + // Also wait for app.started before we connect, to ensure Flutter's + // initialization is all complete. + await appStartedCompleter.future; + await _connectDebugger(vmServiceUri); } - _connectDebuggerIfReady(); } /// Handles the Flutter process exiting, terminating the debug session if it has not already begun terminating. @@ -601,7 +595,7 @@ class FlutterDebugAdapter extends DartDebugAdapter{ - 'appId': _appId, + 'appId': appId, 'fullRestart': fullRestart, 'pause': enableDebugger, 'reason': reason, diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 399aa46d72370..6c55b4599a805 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -42,6 +42,7 @@ import 'web/chrome.dart'; import 'web/web_validator.dart'; import 'web/workflow.dart'; import 'windows/visual_studio_validator.dart'; +import 'windows/windows_version_validator.dart'; import 'windows/windows_workflow.dart'; abstract class DoctorValidatorsProvider { @@ -129,6 +130,9 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { flutterRoot: () => Cache.flutterRoot!, operatingSystemUtils: globals.os, ), + if (platform.isWindows) WindowsVersionValidator( + processManager: globals.processManager, + ), if (androidWorkflow!.appliesToHostPlatform) GroupedValidator([androidValidator!, androidLicenseValidator!]), if (globals.iosWorkflow!.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform) diff --git a/packages/flutter_tools/lib/src/drive/drive_service.dart b/packages/flutter_tools/lib/src/drive/drive_service.dart index 91f0560eea321..d96ee4abb8d08 100644 --- a/packages/flutter_tools/lib/src/drive/drive_service.dart +++ b/packages/flutter_tools/lib/src/drive/drive_service.dart @@ -290,9 +290,9 @@ class FlutterDriverService extends DriverService { }) async { if (writeSkslOnExit != null) { final FlutterView flutterView = (await _vmService.getFlutterViews()).first; - final Map result = await (_vmService.getSkSLs( + final Map? result = await _vmService.getSkSLs( viewId: flutterView.id - ) as FutureOr>); + ); await sharedSkSlWriter(_device!, result, outputFile: writeSkslOnExit, logger: _logger); } // If the application package is available, stop and uninstall. diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index 74a3116b4d4d3..1562375c785b9 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -196,6 +196,12 @@ const Feature flutterCustomDevicesFeature = Feature( master: FeatureChannelSetting( available: true, ), + beta: FeatureChannelSetting( + available: true, + ), + stable: FeatureChannelSetting( + available: true, + ), ); /// The fast hot reload feature for https://github.com/flutter/flutter/issues/61407. diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index f4ce3cd8c3895..4ef0ef317de69 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -234,12 +234,12 @@ class FlutterSdk extends EngineCachedArtifact { if (cache.includeAllPlatforms) ...>[ ['windows-x64', 'windows-x64/artifacts.zip'], ['linux-$arch', 'linux-$arch/artifacts.zip'], - ['darwin-x64', 'darwin-x64/artifacts.zip'], + ['darwin-x64', 'darwin-$arch/artifacts.zip'], ] else if (_platform.isWindows) ['windows-x64', 'windows-x64/artifacts.zip'] else if (_platform.isMacOS) - ['darwin-x64', 'darwin-x64/artifacts.zip'] + ['darwin-x64', 'darwin-$arch/artifacts.zip'] else if (_platform.isLinux) ['linux-$arch', 'linux-$arch/artifacts.zip'], ]; @@ -729,7 +729,7 @@ class FontSubsetArtifacts extends EngineCachedArtifact { // Currently only Linux supports both arm64 and x64. final String arch = cache.getHostPlatformArchName(); final Map> artifacts = > { - 'macos': ['darwin-x64', 'darwin-x64/$artifactName.zip'], + 'macos': ['darwin-x64', 'darwin-$arch/$artifactName.zip'], 'linux': ['linux-$arch', 'linux-$arch/$artifactName.zip'], 'windows': ['windows-x64', 'windows-x64/$artifactName.zip'], }; diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index aaa7e2ef9d0a4..e350ab3cb9be1 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -567,6 +567,7 @@ const String _dartPluginRegistryTemplate = ''' // Generated file. Do not edit. // +// @dart = 2.13 // ignore_for_file: type=lint {{#methodChannelPlugins}} diff --git a/packages/flutter_tools/lib/src/flutter_project_metadata.dart b/packages/flutter_tools/lib/src/flutter_project_metadata.dart index 4e0fa787e27cf..2f3fbe3b6014b 100644 --- a/packages/flutter_tools/lib/src/flutter_project_metadata.dart +++ b/packages/flutter_tools/lib/src/flutter_project_metadata.dart @@ -72,22 +72,21 @@ FlutterProjectType? stringToProjectType(String value) { /// A wrapper around the `.metadata` file. class FlutterProjectMetadata { /// Creates a MigrateConfig by parsing an existing .migrate_config yaml file. - FlutterProjectMetadata(File file, Logger logger) : _metadataFile = file, - _logger = logger, + FlutterProjectMetadata(this.file, Logger logger) : _logger = logger, migrateConfig = MigrateConfig() { - if (!_metadataFile.existsSync()) { - _logger.printTrace('No .metadata file found at ${_metadataFile.path}.'); + if (!file.existsSync()) { + _logger.printTrace('No .metadata file found at ${file.path}.'); // Create a default empty metadata. return; } Object? yamlRoot; try { - yamlRoot = loadYaml(_metadataFile.readAsStringSync()); + yamlRoot = loadYaml(file.readAsStringSync()); } on YamlException { // Handled in _validate below. } if (yamlRoot is! YamlMap) { - _logger.printTrace('.metadata file at ${_metadataFile.path} was empty or malformed.'); + _logger.printTrace('.metadata file at ${file.path} was empty or malformed.'); return; } if (_validateMetadataMap(yamlRoot, {'version': YamlMap}, _logger)) { @@ -109,9 +108,9 @@ class FlutterProjectMetadata { } } - /// Creates a MigrateConfig by explicitly providing all values. + /// Creates a FlutterProjectMetadata by explicitly providing all values. FlutterProjectMetadata.explicit({ - required File file, + required this.file, required String? versionRevision, required String? versionChannel, required FlutterProjectType? projectType, @@ -120,8 +119,7 @@ class FlutterProjectMetadata { }) : _logger = logger, _versionChannel = versionChannel, _versionRevision = versionRevision, - _projectType = projectType, - _metadataFile = file; + _projectType = projectType; /// The name of the config file. static const String kFileName = '.metadata'; @@ -140,17 +138,27 @@ class FlutterProjectMetadata { final Logger _logger; - final File _metadataFile; + final File file; /// Writes the .migrate_config file in the provided project directory's platform subdirectory. /// /// We write the file manually instead of with a template because this /// needs to be able to write the .migrate_config file into legacy apps. void writeFile({File? outputFile}) { - outputFile = outputFile ?? _metadataFile; + outputFile = outputFile ?? file; + if (outputFile == null) { + // In-memory FlutterProjectMetadata instances requires an output file to + // be passed or specified in the constructor. + throw const FileSystemException('No outputFile specified to write .metadata to. Initialize with a file or provide one when writing.'); + } outputFile ..createSync(recursive: true) - ..writeAsStringSync(''' + ..writeAsStringSync(toString(), flush: true); + } + + @override + String toString() { + return ''' # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # @@ -161,13 +169,12 @@ version: channel: $_versionChannel project_type: ${flutterProjectTypeToString(projectType)} -${migrateConfig.getOutputFileString()}''', - flush: true); +${migrateConfig.getOutputFileString()}'''; } void populate({ List? platforms, - Directory? projectDirectory, + required Directory projectDirectory, String? currentRevision, String? createRevision, bool create = true, @@ -205,11 +212,11 @@ ${migrateConfig.getOutputFileString()}''', class MigrateConfig { MigrateConfig({ Map? platformConfigs, - this.unmanagedFiles = _kDefaultUnmanagedFiles + this.unmanagedFiles = kDefaultUnmanagedFiles }) : platformConfigs = platformConfigs ?? {}; /// A mapping of the files that are unmanaged by defult for each platform. - static const List _kDefaultUnmanagedFiles = [ + static const List kDefaultUnmanagedFiles = [ 'lib/main.dart', 'ios/Runner.xcodeproj/project.pbxproj', ]; @@ -222,20 +229,20 @@ class MigrateConfig { /// These files are typically user-owned files that should not be changed. List unmanagedFiles; - bool get isEmpty => platformConfigs.isEmpty && (unmanagedFiles.isEmpty || unmanagedFiles == _kDefaultUnmanagedFiles); + bool get isEmpty => platformConfigs.isEmpty && (unmanagedFiles.isEmpty || unmanagedFiles == kDefaultUnmanagedFiles); /// Parses the project for all supported platforms and populates the [MigrateConfig] /// to reflect the project. void populate({ List? platforms, - Directory? projectDirectory, + required Directory projectDirectory, String? currentRevision, String? createRevision, bool create = true, bool update = true, required Logger logger, }) { - final FlutterProject flutterProject = projectDirectory == null ? FlutterProject.current() : FlutterProject.fromDirectory(projectDirectory); + final FlutterProject flutterProject = FlutterProject.fromDirectory(projectDirectory); platforms ??= flutterProject.getSupportedPlatforms(includeRoot: true); for (final SupportedPlatform platform in platforms) { @@ -245,7 +252,7 @@ class MigrateConfig { } } else { if (create) { - platformConfigs[platform] = MigratePlatformConfig(createRevision: createRevision, baseRevision: currentRevision); + platformConfigs[platform] = MigratePlatformConfig(platform: platform, createRevision: createRevision, baseRevision: currentRevision); } } } @@ -290,10 +297,11 @@ migration: 'create_revision': String, 'base_revision': String, }, logger)) { - final SupportedPlatform platformString = SupportedPlatform.values.firstWhere( + final SupportedPlatform platformValue = SupportedPlatform.values.firstWhere( (SupportedPlatform val) => val.toString() == 'SupportedPlatform.${platformYamlMap['platform'] as String}' ); - platformConfigs[platformString] = MigratePlatformConfig( + platformConfigs[platformValue] = MigratePlatformConfig( + platform: platformValue, createRevision: platformYamlMap['create_revision'] as String?, baseRevision: platformYamlMap['base_revision'] as String?, ); @@ -315,7 +323,14 @@ migration: /// Holds the revisions for a single platform for use by the flutter migrate command. class MigratePlatformConfig { - MigratePlatformConfig({this.createRevision, this.baseRevision}); + MigratePlatformConfig({ + required this.platform, + this.createRevision, + this.baseRevision + }); + + /// The platform this config describes. + SupportedPlatform platform; /// The Flutter SDK revision this platform was created by. /// @@ -326,4 +341,10 @@ class MigratePlatformConfig { /// /// Null if the project was never migrated or the revision is unknown. String? baseRevision; + + bool equals(MigratePlatformConfig other) { + return platform == other.platform && + createRevision == other.createRevision && + baseRevision == other.baseRevision; + } } diff --git a/packages/flutter_tools/lib/src/globals.dart b/packages/flutter_tools/lib/src/globals.dart index 778790fc53d3d..260eaf56653e4 100644 --- a/packages/flutter_tools/lib/src/globals.dart +++ b/packages/flutter_tools/lib/src/globals.dart @@ -248,7 +248,11 @@ PlistParser? _plistInstance; /// The global template renderer. TemplateRenderer get templateRenderer => context.get()!; -ShutdownHooks? get shutdownHooks => context.get(); +/// Global [ShutdownHooks] that should be run before the tool process exits. +/// +/// This is depended on by [localFileSystem] which is called before any +/// [Context] is set up, and thus this cannot be a Context getter. +final ShutdownHooks shutdownHooks = ShutdownHooks(); // Unless we're in a test of this class's signal handling features, we must // have only one instance created with the singleton LocalSignals instance diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 5a3619e7a569a..e9f662905cc25 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -704,7 +704,7 @@ class IOSDeviceLogReader extends DeviceLogReader { void logMessage(vm_service.Event event) { if (_iosDeployDebugger != null && _iosDeployDebugger!.debuggerAttached) { - // Prefer the more complete logs from the attached debugger. + // Prefer the more complete logs from the attached debugger. return; } final String message = processVmServiceMessage(event); diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index 3b703dd4393af..d76cd7e57dcd4 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -176,7 +176,7 @@ Future> _xcodeBuildSettingsLines({ final String engineOutPath = localEngineArtifacts.engineOutPath; xcodeBuildSettings.add('FLUTTER_ENGINE=${globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath))}'); - final String localEngineName = globals.fs.path.basename(engineOutPath); + final String localEngineName = localEngineArtifacts.localEngineName; xcodeBuildSettings.add('LOCAL_ENGINE=$localEngineName'); // Tell Xcode not to build universal binaries for local engines, which are diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 7980039e2c1db..beebd432987d9 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart @@ -161,7 +161,7 @@ class XcodeProjectInterpreter { /// to run outside the x86 Rosetta translation, which may cause crashes. List xcrunCommand() { final List xcrunCommand = []; - if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { + if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) { // Force Xcode commands to run outside Rosetta. xcrunCommand.addAll([ '/usr/bin/arch', diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index de02021eff242..54d416c8db3c6 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -52,18 +52,18 @@ typedef DwdsLauncher = Future Function({ required LoadStrategy loadStrategy, required bool enableDebugging, ExpressionCompiler? expressionCompiler, - bool? enableDebugExtension, - String? hostname, - bool? useSseForDebugProxy, - bool? useSseForDebugBackend, - bool? useSseForInjectedClient, + bool enableDebugExtension, + String hostname, + bool useSseForDebugProxy, + bool useSseForDebugBackend, + bool useSseForInjectedClient, UrlEncoder? urlEncoder, - bool? spawnDds, - bool? enableDevtoolsLaunch, + bool spawnDds, + bool enableDevtoolsLaunch, DevtoolsLauncher? devtoolsLauncher, - bool? launchDevToolsInNewWindow, + bool launchDevToolsInNewWindow, SdkConfigurationProvider? sdkConfigurationProvider, - bool? emitDebugEvents, + bool emitDebugEvents, }); // A minimal index for projects that do not yet support web. @@ -296,6 +296,7 @@ class WebAssetServer implements AssetReader { loadStrategy: FrontendServerRequireStrategyProvider( ReloadConfiguration.none, server, + PackageUriMapper(packageConfig), digestProvider, server.basePath!, ).strategy, @@ -1042,7 +1043,12 @@ void log(logging.LogRecord event) { if (event.level >= logging.Level.SEVERE) { globals.printError('${event.loggerName}: ${event.message}$error', stackTrace: event.stackTrace); } else if (event.level == logging.Level.WARNING) { - globals.printWarning('${event.loggerName}: ${event.message}$error'); + // Note: Temporary fix for https://github.com/flutter/flutter/issues/109792 + // TODO(annagrin): Remove the condition after the bogus warning is + // removed in dwds: https://github.com/dart-lang/webdev/issues/1722 + if (!event.message.contains('No module for')) { + globals.printWarning('${event.loggerName}: ${event.message}$error'); + } } else { globals.printTrace('${event.loggerName}: ${event.message}$error'); } diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index ac259be640d73..501606484a7c3 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -81,14 +81,14 @@ const String kExitMessage = 'Failed to establish connection with the application class ResidentWebRunner extends ResidentRunner { ResidentWebRunner( - FlutterDevice? device, { + FlutterDevice device, { String? target, bool stayResident = true, bool machine = false, required this.flutterProject, required bool? ipv6, required DebuggingOptions debuggingOptions, - required FileSystem? fileSystem, + required FileSystem fileSystem, required Logger? logger, required SystemClock systemClock, required Usage usage, @@ -100,8 +100,8 @@ class ResidentWebRunner extends ResidentRunner { _usage = usage, _urlTunneller = urlTunneller, super( - [device], - target: target ?? fileSystem!.path.join('lib', 'main.dart'), + [device], + target: target ?? fileSystem.path.join('lib', 'main.dart'), debuggingOptions: debuggingOptions, ipv6: ipv6, stayResident: stayResident, @@ -109,7 +109,7 @@ class ResidentWebRunner extends ResidentRunner { devtoolsHandler: devtoolsHandler, ); - final FileSystem? _fileSystem; + final FileSystem _fileSystem; final Logger? _logger; final SystemClock _systemClock; final Usage _usage; @@ -119,7 +119,7 @@ class ResidentWebRunner extends ResidentRunner { Logger? get logger => _logger; @override - FileSystem? get fileSystem => _fileSystem; + FileSystem get fileSystem => _fileSystem; FlutterDevice? get device => flutterDevices.first; final FlutterProject flutterProject; @@ -245,7 +245,7 @@ class ResidentWebRunner extends ResidentRunner { } final String modeName = debuggingOptions.buildInfo.friendlyModeName; _logger!.printStatus( - 'Launching ${getDisplayPath(target, _fileSystem!)} ' + 'Launching ${getDisplayPath(target, _fileSystem)} ' 'on ${device!.device!.name} in $modeName mode...', ); if (device!.device is ChromiumDevice) { @@ -271,7 +271,7 @@ class ResidentWebRunner extends ResidentRunner { buildInfo: debuggingOptions.buildInfo, enableDwds: _enableDwds, enableDds: debuggingOptions.enableDds, - entrypoint: _fileSystem!.file(target).uri, + entrypoint: _fileSystem.file(target).uri, expressionCompiler: expressionCompiler, chromiumLauncher: _chromiumLauncher, nullAssertions: debuggingOptions.nullAssertions, @@ -280,6 +280,7 @@ class ResidentWebRunner extends ResidentRunner { ); final Uri url = await device!.devFS!.create(); if (debuggingOptions.buildInfo.isDebug) { + await runSourceGenerators(); final UpdateFSReport report = await _updateDevFS(fullRestart: true); if (!report.success) { _logger!.printError('Failed to compile application.'); @@ -425,7 +426,7 @@ class ResidentWebRunner extends ResidentRunner { Future _generateEntrypoint(Uri mainUri, PackageConfig? packageConfig) async { File? result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart'); if (_generatedEntrypointDirectory == null) { - _generatedEntrypointDirectory ??= _fileSystem!.systemTempDirectory.createTempSync('flutter_tools.') + _generatedEntrypointDirectory ??= _fileSystem.systemTempDirectory.createTempSync('flutter_tools.') ..createSync(); result = _generatedEntrypointDirectory!.childFile('web_entrypoint.dart'); @@ -438,16 +439,17 @@ class ResidentWebRunner extends ResidentRunner { Uri? importedEntrypoint = packageConfig!.toPackageUri(mainUri); // Special handling for entrypoints that are not under lib, such as test scripts. if (importedEntrypoint == null) { - final String parent = _fileSystem!.file(mainUri).parent.path; - flutterDevices.first!.generator!.addFileSystemRoot(parent); - flutterDevices.first!.generator!.addFileSystemRoot(_fileSystem!.directory('test').absolute.path); + final String parent = _fileSystem.file(mainUri).parent.path; + flutterDevices.first.generator! + ..addFileSystemRoot(parent) + ..addFileSystemRoot(_fileSystem.directory('test').absolute.path); importedEntrypoint = Uri( scheme: 'org-dartlang-app', path: '/${mainUri.pathSegments.last}', ); } final LanguageVersion languageVersion = determineLanguageVersion( - _fileSystem!.file(mainUri), + _fileSystem.file(mainUri), packageConfig[flutterProject.manifest.appName], Cache.flutterRoot!, ); @@ -487,7 +489,7 @@ class ResidentWebRunner extends ResidentRunner { ); final UpdateFSReport report = await device!.devFS!.update( mainUri: await _generateEntrypoint( - _fileSystem!.file(mainPath).absolute.uri, + _fileSystem.file(mainPath).absolute.uri, invalidationResult.packageConfig, ), target: target, @@ -521,7 +523,7 @@ class ResidentWebRunner extends ResidentRunner { final Chromium chrome = await _chromiumLauncher!.connectedInstance; final ChromeTab chromeTab = await (chrome.chromeConnection.getTab((ChromeTab chromeTab) { return !chromeTab.url.startsWith('chrome-extension'); - }) as FutureOr); + }, retryFor: const Duration(seconds: 5)) as FutureOr); if (chromeTab == null) { throwToolExit('Failed to connect to Chrome instance.'); } @@ -603,7 +605,7 @@ class ResidentWebRunner extends ResidentRunner { } if (websocketUri != null) { if (debuggingOptions.vmserviceOutFile != null) { - _fileSystem!.file(debuggingOptions.vmserviceOutFile) + _fileSystem.file(debuggingOptions.vmserviceOutFile) ..createSync(recursive: true) ..writeAsStringSync(websocketUri.toString()); } diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 062fea300374b..12fc35b531319 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -60,7 +60,7 @@ Future buildLinux( final LocalEngineArtifacts localEngineArtifacts = artifacts; final String engineOutPath = localEngineArtifacts.engineOutPath; environmentConfig['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); - environmentConfig['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath); + environmentConfig['LOCAL_ENGINE'] = localEngineArtifacts.localEngineName; } writeGeneratedCmakeConfig(Cache.flutterRoot!, linuxProject, buildInfo, environmentConfig); diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 208c2866dea44..e14fbdd17b9ef 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -811,6 +811,10 @@ class LocalizationsGenerator { return _allBundles.bundles.map((AppResourceBundle bundle) => bundle.file.path).toList(); } + List get outputFileList { + return _outputFileList; + } + /// The supported language codes as found in the arb files located in /// [inputDirectory]. final Set supportedLanguageCodes = {}; @@ -1339,7 +1343,7 @@ class LocalizationsGenerator { || message.placeholdersRequireFormatting; }); - void writeOutputFiles({ bool isFromYaml = false }) { + List writeOutputFiles({ bool isFromYaml = false }) { // First, generate the string contents of all necessary files. final String generatedLocalizationsFile = _generateCode(); @@ -1372,9 +1376,7 @@ class LocalizationsGenerator { // Generate the required files for localizations. _languageFileMap.forEach((File file, String contents) { file.writeAsStringSync(contents); - if (inputsAndOutputsListFile != null) { - _outputFileList.add(file.absolute.path); - } + _outputFileList.add(file.absolute.path); }); baseOutputFile.writeAsStringSync(generatedLocalizationsFile); @@ -1407,9 +1409,8 @@ class LocalizationsGenerator { ); } final File? inputsAndOutputsListFileLocal = inputsAndOutputsListFile; + _outputFileList.add(baseOutputFile.absolute.path); if (inputsAndOutputsListFileLocal != null) { - _outputFileList.add(baseOutputFile.absolute.path); - // Generate a JSON file containing the inputs and outputs of the gen_l10n script. if (!inputsAndOutputsListFileLocal.existsSync()) { inputsAndOutputsListFileLocal.createSync(recursive: true); @@ -1422,14 +1423,14 @@ class LocalizationsGenerator { }), ); } + + return _outputFileList; } void _generateUntranslatedMessagesFile(Logger logger, File untranslatedMessagesFile) { if (_unimplementedMessages.isEmpty) { untranslatedMessagesFile.writeAsStringSync('{}'); - if (inputsAndOutputsListFile != null) { - _outputFileList.add(untranslatedMessagesFile.absolute.path); - } + _outputFileList.add(untranslatedMessagesFile.absolute.path); return; } @@ -1457,8 +1458,6 @@ class LocalizationsGenerator { resultingFile += '}\n'; untranslatedMessagesFile.writeAsStringSync(resultingFile); - if (inputsAndOutputsListFile != null) { - _outputFileList.add(untranslatedMessagesFile.absolute.path); - } + _outputFileList.add(untranslatedMessagesFile.absolute.path); } } diff --git a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart index a8e413526670e..d001c56026e4c 100644 --- a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart +++ b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart @@ -311,6 +311,7 @@ class LocalizationOptions { this.useSyntheticPackage = true, this.areResourceAttributesRequired = false, this.usesNullableGetter = true, + this.format = false, }) : assert(useSyntheticPackage != null); /// The `--arb-dir` argument. @@ -377,6 +378,11 @@ class LocalizationOptions { /// /// Whether or not the localizations class getter is nullable. final bool usesNullableGetter; + + /// The `format` argument. + /// + /// Whether or not to format the generated files. + final bool format; } /// Parse the localizations configuration options from [file]. @@ -411,6 +417,7 @@ LocalizationOptions parseLocalizationsOptions({ useSyntheticPackage: _tryReadBool(yamlNode, 'synthetic-package', logger) ?? true, areResourceAttributesRequired: _tryReadBool(yamlNode, 'required-resource-attributes', logger) ?? false, usesNullableGetter: _tryReadBool(yamlNode, 'nullable-getter', logger) ?? true, + format: _tryReadBool(yamlNode, 'format', logger) ?? true, ); } diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index bc7591c33667a..a131de0fc2a4f 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -362,7 +362,7 @@ class CocoaPods { emphasis: true, ); } else if ((stderr.contains('ffi_c.bundle') || stderr.contains('/ffi/')) && - _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { + _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) { // https://github.com/flutter/flutter/issues/70796 UsageEvent( 'pod-install-failure', diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart index 405202ad4f9ea..c0a49a7e6feaa 100644 --- a/packages/flutter_tools/lib/src/macos/macos_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_device.dart @@ -52,7 +52,7 @@ class MacOSDevice extends DesktopDevice { @override Future get targetPlatformDisplayName async { - if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { + if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) { return 'darwin-arm64'; } else { return 'darwin-x64'; diff --git a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart index 6943e90325e99..eb2331db9d667 100644 --- a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart @@ -47,11 +47,11 @@ class MacOSDesignedForIPadDevice extends DesktopDevice { Future get targetPlatform async => TargetPlatform.darwin; @override - bool isSupported() => _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm; + bool isSupported() => _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64; @override bool isSupportedForProject(FlutterProject flutterProject) { - return flutterProject.ios.existsSync() && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm; + return flutterProject.ios.existsSync() && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64; } @override @@ -119,7 +119,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { /// and discovery is allowed for this command. @override bool get canListAnything => - _iosWorkflow.canListDevices && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm && allowDiscovery; + _iosWorkflow.canListDevices && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64 && allowDiscovery; /// Set to show ARM macOS as an iOS device target. static bool allowDiscovery = false; diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index fa7212f705920..86c11e49fa8d2 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -165,16 +165,17 @@ class Xcode { /// See [XcodeProjectInterpreter.xcrunCommand]. List xcrunCommand() => _xcodeProjectInterpreter.xcrunCommand(); - Future cc(List args) { - return _processUtils.run( - [...xcrunCommand(), 'cc', ...args], - throwOnError: true, - ); - } + Future cc(List args) => _run('cc', args); + + Future clang(List args) => _run('clang', args); + + Future dsymutil(List args) => _run('dsymutil', args); + + Future strip(List args) => _run('strip', args); - Future clang(List args) { + Future _run(String command, List args) { return _processUtils.run( - [...xcrunCommand(), 'clang', ...args], + [...xcrunCommand(), command, ...args], throwOnError: true, ); } diff --git a/packages/flutter_tools/lib/src/mdns_discovery.dart b/packages/flutter_tools/lib/src/mdns_discovery.dart index 13882b923bded..a1d0717e1d2f6 100644 --- a/packages/flutter_tools/lib/src/mdns_discovery.dart +++ b/packages/flutter_tools/lib/src/mdns_discovery.dart @@ -41,7 +41,7 @@ class MDnsObservatoryDiscovery { /// Executes an mDNS query for a Dart Observatory. /// /// The [applicationId] parameter may be used to specify which application - /// to find. For Android, it refers to the package name; on iOS, it refers to + /// to find. For Android, it refers to the package name; on iOS, it refers to /// the bundle ID. /// /// If it is not null, this method will find the port and authentication code diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 3f575688a7028..de428242089a6 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -240,7 +240,7 @@ class FlutterDevice { bool cacheStartupProfile = false, bool enableDds = true, required bool allowExistingDdsInstance, - bool? ipv6 = false, + bool ipv6 = false, }) { final Completer completer = Completer(); late StreamSubscription subscription; @@ -927,13 +927,13 @@ abstract class ResidentHandlers { if (!supportsWriteSkSL) { throw Exception('writeSkSL is not supported by this runner.'); } - final List views = await flutterDevices - .first! - .vmService!.getFlutterViews(); - final Map data = await (flutterDevices.first!.vmService!.getSkSLs( + final FlutterDevice flutterDevice = flutterDevices.first!; + final FlutterVmService vmService = flutterDevice.vmService!; + final List views = await vmService.getFlutterViews(); + final Map? data = await vmService.getSkSLs( viewId: views.first.id, - ) as FutureOr>); - final Device device = flutterDevices.first!.device!; + ); + final Device device = flutterDevice.device!; return sharedSkSlWriter(device, data); } @@ -1091,10 +1091,10 @@ abstract class ResidentRunner extends ResidentHandlers { Logger? get logger => globals.logger; @override - FileSystem? get fileSystem => globals.fs; + FileSystem get fileSystem => globals.fs; @override - final List flutterDevices; + final List flutterDevices; final String target; final DebuggingOptions debuggingOptions; @@ -1171,7 +1171,7 @@ abstract class ResidentRunner extends ResidentHandlers { // // Would be null if there is no device connected or // there is no devFS associated with the first device. - Uri? get uri => flutterDevices.first?.devFS?.baseUri; + Uri? get uri => flutterDevices.first.devFS?.baseUri; /// Returns [true] if the resident runner exited after invoking [exit()]. bool get exited => _exited; @@ -1257,7 +1257,7 @@ abstract class ResidentRunner extends ResidentHandlers { void writeVmServiceFile() { if (debuggingOptions.vmserviceOutFile != null) { try { - final String address = flutterDevices.first!.vmService!.wsAddress.toString(); + final String address = flutterDevices.first.vmService!.wsAddress.toString(); final File vmserviceOutFile = globals.fs.file(debuggingOptions.vmserviceOutFile); vmserviceOutFile.createSync(recursive: true); vmserviceOutFile.writeAsStringSync(address); @@ -1359,7 +1359,7 @@ abstract class ResidentRunner extends ResidentHandlers { hostVmServicePort: debuggingOptions.hostVmServicePort, getSkSLMethod: getSkSLMethod, printStructuredErrorLogMethod: printStructuredErrorLog, - ipv6: ipv6, + ipv6: ipv6 ?? false, disableServiceAuthCodes: debuggingOptions.disableServiceAuthCodes, cacheStartupProfile: debuggingOptions.cacheStartupProfile, ); diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart index 8f1ae56e6a7a0..47577634648d6 100644 --- a/packages/flutter_tools/lib/src/run_cold.dart +++ b/packages/flutter_tools/lib/src/run_cold.dart @@ -88,11 +88,11 @@ class ColdRunner extends ResidentRunner { )); } - if (flutterDevices.first!.observatoryUris != null) { + if (flutterDevices.first.observatoryUris != null) { // For now, only support one debugger connection. connectionInfoCompleter?.complete(DebugConnectionInfo( - httpUri: flutterDevices.first!.vmService!.httpAddress, - wsUri: flutterDevices.first!.vmService!.wsAddress, + httpUri: flutterDevices.first.vmService!.httpAddress, + wsUri: flutterDevices.first.vmService!.wsAddress, )); } @@ -108,7 +108,7 @@ class ColdRunner extends ResidentRunner { if (traceStartup) { // Only trace startup for the first device. - final FlutterDevice device = flutterDevices.first!; + final FlutterDevice device = flutterDevices.first; if (device.vmService != null) { globals.printStatus('Tracing startup on ${device.device!.name}.'); final String outputPath = globals.platform.environment[kFlutterTestOutputsDirEnvName] ?? getBuildDirectory(); diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 5ced6432c0d15..763819baca7fe 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -141,7 +141,7 @@ class HotRunner extends ResidentRunner { } if (flutterDevices.length == 1) { - final Device device = flutterDevices.first!.device!; + final Device device = flutterDevices.first.device!; _targetPlatform = getNameForTargetPlatform(await device.targetPlatform); _sdkName = await device.sdkNameAndVersion; _emulator = await device.isLocalEmulator; @@ -257,8 +257,8 @@ class HotRunner extends ResidentRunner { // Only handle one debugger connection. connectionInfoCompleter.complete( DebugConnectionInfo( - httpUri: flutterDevices.first!.vmService!.httpAddress, - wsUri: flutterDevices.first!.vmService!.wsAddress, + httpUri: flutterDevices.first.vmService!.httpAddress, + wsUri: flutterDevices.first.vmService!.wsAddress, baseUri: baseUris.first.toString(), ), ); @@ -454,12 +454,13 @@ class HotRunner extends ResidentRunner { } final Stopwatch findInvalidationTimer = _stopwatchFactory.createStopwatch('updateDevFS')..start(); + final DevFS devFS = flutterDevices[0].devFS!; final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated( - lastCompiled: flutterDevices[0]!.devFS!.lastCompiled, - urisToMonitor: flutterDevices[0]!.devFS!.sources, + lastCompiled: devFS.lastCompiled, + urisToMonitor: devFS.sources, packagesPath: packagesFilePath, asyncScanning: hotRunnerConfig!.asyncScanning, - packageConfig: flutterDevices[0]!.devFS!.lastPackageConfig + packageConfig: devFS.lastPackageConfig ?? debuggingOptions.buildInfo.packageConfig, ); findInvalidationTimer.stop(); @@ -474,7 +475,7 @@ class HotRunner extends ResidentRunner { } final UpdateFSReport results = UpdateFSReport( success: true, - scannedSourcesCount: flutterDevices[0]!.devFS!.sources.length, + scannedSourcesCount: devFS.sources.length, findInvalidatedDuration: findInvalidationTimer.elapsed, ); for (final FlutterDevice? device in flutterDevices) { @@ -497,21 +498,27 @@ class HotRunner extends ResidentRunner { } void _resetDirtyAssets() { - for (final FlutterDevice? device in flutterDevices) { - device!.devFS!.assetPathsToEvict.clear(); - device.devFS!.shaderPathsToEvict.clear(); + for (final FlutterDevice device in flutterDevices) { + final DevFS? devFS = device.devFS; + if (devFS == null) { + // This is sometimes null, however we don't know why and have not been + // able to reproduce, https://github.com/flutter/flutter/issues/108653 + continue; + } + devFS.assetPathsToEvict.clear(); + devFS.shaderPathsToEvict.clear(); } } Future _cleanupDevFS() async { final List> futures = >[]; - for (final FlutterDevice? device in flutterDevices) { - if (device!.devFS != null) { + for (final FlutterDevice device in flutterDevices) { + if (device.devFS != null) { // Cleanup the devFS, but don't wait indefinitely. // We ignore any errors, because it's not clear what we would do anyway. futures.add(device.devFS!.destroy() .timeout(const Duration(milliseconds: 250)) - .catchError((dynamic error) { + .catchError((Object? error) { globals.printTrace('Ignored error while cleaning up DevFS: $error'); })); } @@ -756,7 +763,7 @@ class HotRunner extends ResidentRunner { String? restartEvent; try { final Stopwatch restartTimer = _stopwatchFactory.createStopwatch('fullRestartHelper')..start(); - if (!(await (hotRunnerConfig!.setupHotRestart() as FutureOr))) { + if ((await hotRunnerConfig!.setupHotRestart()) != true) { return OperationResult(1, 'setupHotRestart failed'); } result = await _restartFromSources(reason: reason); @@ -885,7 +892,7 @@ class HotRunner extends ResidentRunner { } final Stopwatch reloadTimer = _stopwatchFactory.createStopwatch('reloadSources:reload')..start(); - if (!(await (hotRunnerConfig!.setupHotReload() as FutureOr))) { + if ((await hotRunnerConfig!.setupHotReload()) != true) { return OperationResult(1, 'setupHotReload failed'); } final Stopwatch devFSTimer = Stopwatch()..start(); diff --git a/packages/flutter_tools/lib/src/runner/local_engine.dart b/packages/flutter_tools/lib/src/runner/local_engine.dart index ecdad2fa14908..e0fcb819a8218 100644 --- a/packages/flutter_tools/lib/src/runner/local_engine.dart +++ b/packages/flutter_tools/lib/src/runner/local_engine.dart @@ -18,7 +18,7 @@ import '../dart/package_map.dart'; /// The flutter tool can be run with the output files of one or more engine builds /// replacing the cached artifacts. Typically this is done by setting the /// `--local-engine` command line flag to the name of the desired engine variant -/// (e.g. "host_debug_unopt"). Provided that the `flutter/` and `engine/` directories +/// (e.g. "host_debug_unopt"). Provided that the `flutter/` and `engine/` directories /// are located adjacent to one another, the output folder will be located /// automatically. /// diff --git a/packages/flutter_tools/lib/src/sksl_writer.dart b/packages/flutter_tools/lib/src/sksl_writer.dart index aab82c0c8079a..82701743f6659 100644 --- a/packages/flutter_tools/lib/src/sksl_writer.dart +++ b/packages/flutter_tools/lib/src/sksl_writer.dart @@ -13,12 +13,12 @@ import 'convert.dart'; import 'device.dart'; import 'globals.dart' as globals; -Future sharedSkSlWriter(Device device, Map data, { +Future sharedSkSlWriter(Device device, Map? data, { File? outputFile, Logger? logger, }) async { logger ??= globals.logger; - if (data.isEmpty) { + if (data == null || data.isEmpty) { logger.printStatus( 'No data was received. To ensure SkSL data can be generated use a ' 'physical device then:\n' diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index f8804d6f78d37..eea5f7a1252ed 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart @@ -6,6 +6,7 @@ import 'dart:async'; +import 'package:dds/dds.dart'; import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import 'package:stream_channel/stream_channel.dart'; @@ -65,6 +66,7 @@ FlutterPlatform installHook({ Device? integrationTestDevice, String? integrationTestUserIdentifier, TestTimeRecorder? testTimeRecorder, + UriConverter? uriConverter, }) { assert(testWrapper != null); assert(enableObservatory || (!debuggingOptions.startPaused && debuggingOptions.hostVmServicePort == null)); @@ -95,6 +97,7 @@ FlutterPlatform installHook({ integrationTestDevice: integrationTestDevice, integrationTestUserIdentifier: integrationTestUserIdentifier, testTimeRecorder: testTimeRecorder, + uriConverter: uriConverter, ); platformPluginRegistration(platform); return platform; @@ -290,6 +293,7 @@ class FlutterPlatform extends PlatformPlugin { this.integrationTestDevice, this.integrationTestUserIdentifier, this.testTimeRecorder, + this.uriConverter, }) : assert(shellPath != null); final String shellPath; @@ -307,6 +311,9 @@ class FlutterPlatform extends PlatformPlugin { final String? icudtlPath; final TestTimeRecorder? testTimeRecorder; + // This can be used by internal projects that require custom logic for converting package: URIs to local paths. + final UriConverter? uriConverter; + /// The device to run the test on for Integration Tests. /// /// If this is null, the test will run as a regular test with the Flutter @@ -428,7 +435,8 @@ class FlutterPlatform extends PlatformPlugin { flutterProject: flutterProject, icudtlPath: icudtlPath, compileExpression: _compileExpressionService, - fontConfigManager: _fontConfigManager + fontConfigManager: _fontConfigManager, + uriConverter: uriConverter, ); } diff --git a/packages/flutter_tools/lib/src/test/flutter_tester_device.dart b/packages/flutter_tools/lib/src/test/flutter_tester_device.dart index 1a243ba5efae3..14cdfc02451a8 100644 --- a/packages/flutter_tools/lib/src/test/flutter_tester_device.dart +++ b/packages/flutter_tools/lib/src/test/flutter_tester_device.dart @@ -15,7 +15,6 @@ import 'package:stream_channel/stream_channel.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; -import '../base/os.dart'; import '../base/platform.dart'; import '../convert.dart'; import '../device.dart'; @@ -44,16 +43,11 @@ class FlutterTesterTestDevice extends TestDevice { required this.icudtlPath, required this.compileExpression, required this.fontConfigManager, + required this.uriConverter, }) : assert(shellPath != null), // Please provide the path to the shell in the SKY_SHELL environment variable. assert(!debuggingOptions.startPaused || enableObservatory), _gotProcessObservatoryUri = enableObservatory - ? Completer() : (Completer()..complete()), - _operatingSystemUtils = OperatingSystemUtils( - fileSystem: fileSystem, - logger: logger, - platform: platform, - processManager: processManager, - ); + ? Completer() : (Completer()..complete()); /// Used for logging to identify the test that is currently being executed. final int id; @@ -71,13 +65,13 @@ class FlutterTesterTestDevice extends TestDevice { final String? icudtlPath; final CompileExpression? compileExpression; final FontConfigManager fontConfigManager; + final UriConverter? uriConverter; final Completer _gotProcessObservatoryUri; final Completer _exitCode = Completer(); Process? _process; HttpServer? _server; - final OperatingSystemUtils _operatingSystemUtils; /// Starts the device. /// @@ -94,13 +88,6 @@ class FlutterTesterTestDevice extends TestDevice { _server = await bind(host, /*port*/ 0); logger.printTrace('test $id: test harness socket server is running at port:${_server!.port}'); final List command = [ - // Until an arm64 flutter tester binary is available, force to run in Rosetta - // to avoid "unexpectedly got a signal in sigtramp" crash. - // https://github.com/flutter/flutter/issues/88106 - if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) ...[ - '/usr/bin/arch', - '-x86_64', - ], shellPath, if (enableObservatory) ...[ // Some systems drive the _FlutterPlatform class in an unusual way, where @@ -177,7 +164,10 @@ class FlutterTesterTestDevice extends TestDevice { Uri? forwardingUri; if (debuggingOptions.enableDds) { logger.printTrace('test $id: Starting Dart Development Service'); - final DartDevelopmentService dds = await startDds(detectedUri); + final DartDevelopmentService dds = await startDds( + detectedUri, + uriConverter: uriConverter, + ); forwardingUri = dds.uri; logger.printTrace('test $id: Dart Development Service started at ${dds.uri}, forwarding to VM service at ${dds.remoteVmServiceUri}.'); } else { @@ -254,12 +244,13 @@ class FlutterTesterTestDevice extends TestDevice { @visibleForTesting @protected - Future startDds(Uri uri) { + Future startDds(Uri uri, {UriConverter? uriConverter}) { return DartDevelopmentService.startDartDevelopmentService( uri, serviceUri: _ddsServiceUri, enableAuthCodes: !debuggingOptions.disableServiceAuthCodes, ipv6: host!.type == InternetAddressType.IPv6, + uriConverter: uriConverter, ); } diff --git a/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart b/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart index 74c37a786bb4f..ea23742eb6277 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_goldens.dart @@ -56,7 +56,7 @@ class TestGoldenComparator { /// to reduce the overhead of starting `flutter_tester`. Future _processForTestFile(Uri testUri) async { if (testUri == _previousTestUri) { - return _previousComparator; + return _previousComparator!; } final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(_fileSystem.file(testUri), testUri, logger: _logger); @@ -68,7 +68,7 @@ class TestGoldenComparator { _previousComparator = TestGoldenComparatorProcess(process, logger: _logger); _previousTestUri = testUri; - return _previousComparator; + return _previousComparator!; } Future _startProcess(String testBootstrap) async { @@ -100,7 +100,11 @@ class TestGoldenComparator { Future compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool? updateGoldens) async { final File imageFile = await (await tempDir.createTemp('image')).childFile('image').writeAsBytes(bytes); - final TestGoldenComparatorProcess process = await (_processForTestFile(testUri) as FutureOr); + final TestGoldenComparatorProcess? process = await _processForTestFile(testUri); + if (process == null) { + return 'process was null'; + } + process.sendCommand(imageFile, goldenKey, updateGoldens); final Map result = await process.getResponse(); diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index 6c6c7e4f2127b..5887b715e353b 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -327,7 +327,7 @@ class FlutterVersion { } /// log.showSignature=false is a user setting and it will break things, - /// so we want to disable it for every git log call. This is a convenience + /// so we want to disable it for every git log call. This is a convenience /// wrapper that does that. @visibleForTesting static List gitLog(List args) { @@ -812,9 +812,9 @@ class GitTagVersion { return '$x.$y.$z+hotfix.${hotfix! + 1}.pre.$commits'; } if (devPatch != null && devVersion != null) { - // The next published release this commit will appear in will be a beta - // release, thus increment [y]. - return '$x.${y! + 1}.0-0.0.pre.$commits'; + // The next tag that will contain this commit will be the next candidate + // branch, which will increment the devVersion. + return '$x.$y.0-${devVersion! + 1}.0.pre.$commits'; } return '$x.$y.${z! + 1}-0.0.pre.$commits'; } diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index dc5f0519b3026..1d1d5c7fc178e 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -493,7 +493,7 @@ class FlutterVmService { /// /// This method will only return data if `--cache-sksl` was provided as a /// flutter run argument, and only then on physical devices. - Future?> getSkSLs({ + Future?> getSkSLs({ required String viewId, }) async { final vm_service.Response? response = await callMethodWrapper( @@ -505,7 +505,7 @@ class FlutterVmService { if (response == null) { return null; } - return response.json?['SkSLs'] as Map?; + return response.json?['SkSLs'] as Map?; } /// Flush all tasks on the UI thread for an attached Flutter view. diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 43a1e2f60e6ea..a54d930532ca4 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -240,7 +240,7 @@ class ChromiumLauncher { } Future _spawnChromiumProcess(List args, String chromeExecutable) async { - if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { + if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) { final ProcessResult result = _processManager.runSync(['file', chromeExecutable]); // Check if ARM Chrome is installed. // Mach-O 64-bit executable arm64 diff --git a/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart b/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart index 6c8020a97837f..90dfedabed374 100644 --- a/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart +++ b/packages/flutter_tools/lib/src/web/file_generators/flutter_js.dart @@ -205,6 +205,8 @@ _flutter.loader = null; this._didCreateEngineInitializerResolve(engineInitializer); // Remove the resolver after the first time, so Flutter Web can hot restart. this._didCreateEngineInitializerResolve = null; + // Make the engine revert to "auto" initialization on hot restart. + delete _flutter.loader.didCreateEngineInitializer; } if (typeof this._onEntrypointLoaded === "function") { this._onEntrypointLoaded(engineInitializer); diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index e46924edd0d4d..6c2b985aee167 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -221,7 +221,7 @@ void _writeGeneratedFlutterConfig( if (artifacts is LocalEngineArtifacts) { final String engineOutPath = artifacts.engineOutPath; environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); - environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath); + environment['LOCAL_ENGINE'] = artifacts.localEngineName; } writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, buildInfo, environment); } diff --git a/packages/flutter_tools/lib/src/windows/windows_version_validator.dart b/packages/flutter_tools/lib/src/windows/windows_version_validator.dart new file mode 100644 index 0000000000000..27f6cd243dc75 --- /dev/null +++ b/packages/flutter_tools/lib/src/windows/windows_version_validator.dart @@ -0,0 +1,89 @@ +// Copyright 2014 The Flutter Authors. 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:process/process.dart'; + +import '../base/io.dart'; +import '../doctor_validator.dart'; + +const List unsupportedVersions = [ + '6', + '7', + '8', +]; + +/// Validator to be run with `flutter doctor` to check +/// Windows host machines if they are running supported versions. +class WindowsVersionValidator extends DoctorValidator { + const WindowsVersionValidator({required ProcessManager processManager}) + : _processManager = processManager, + super('Windows Version'); + + final ProcessManager _processManager; + + /// Provide a literal string as the Regex pattern + /// and a string to validate and get a boolean determining + /// if the string has at least one match + static Iterable validateString(String pattern, String str, + {bool multiLine = true}) { + final RegExp regex = RegExp( + pattern, + multiLine: multiLine, + ); + + return regex.allMatches(str); + } + + @override + Future validate() async { + final ProcessResult result; + try { + result = await _processManager.run(['systeminfo']); + } on ProcessException { + return const ValidationResult( + ValidationType.missing, + [], + statusInfo: + 'Unable to run Windows version check using built-in `systeminfo`', + ); + } + + if (result.exitCode != 0) { + return const ValidationResult( + ValidationType.missing, + [], + statusInfo: 'Exit status from running `systeminfo` was unsuccessful', + ); + } + + final String resultStdout = result.stdout as String; + + // Regular expression pattern for identifying + // semantic versioned strings + // (ie. 10.5.4123) + final Iterable matches = validateString( + r'^(OS Version:\s*)([0-9]+\.[0-9]+\.[0-9]+)(.*)$', resultStdout); + + // Use the string split method to extract the major version + // and check against the [unsupportedVersions] list + final ValidationType windowsVersionStatus; + String statusInfo; + if (matches.length == 1 && + !unsupportedVersions + .contains(matches.elementAt(0).group(2)?.split('.').elementAt(0))) { + windowsVersionStatus = ValidationType.installed; + statusInfo = 'Installed version of Windows is version 10 or higher'; + } else { + windowsVersionStatus = ValidationType.missing; + statusInfo = + 'Unable to confirm if installed Windows version is 10 or greater'; + } + + return ValidationResult( + windowsVersionStatus, + const [], + statusInfo: statusInfo, + ); + } +} diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 0ed4df509b2e8..65a1666eb4dc8 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -11,17 +11,17 @@ dependencies: args: 2.3.1 browser_launcher: 1.1.1 dds: 2.2.6 - dwds: 15.0.0 + dwds: 16.0.0 completion: 1.0.0 coverage: 1.5.0 crypto: 3.0.2 - file: 6.1.3 + file: 6.1.4 flutter_template_images: 4.2.0 html: 0.15.0 http: 0.13.5 intl: 0.17.0 meta: 1.8.0 - multicast_dns: 0.3.2+1 + multicast_dns: 0.3.2+2 mustache_template: 2.0.0 package_config: 2.1.0 process: 4.2.4 @@ -29,10 +29,10 @@ dependencies: stack_trace: 1.10.0 usage: 4.1.0 webdriver: 3.0.0 - webkit_inspection_protocol: 1.1.0 + webkit_inspection_protocol: 1.2.0 xml: 6.1.0 yaml: 3.1.1 - native_stack_traces: 0.5.0 + native_stack_traces: 0.5.2 shelf: 1.3.2 vm_snapshot_analysis: 0.7.2 uuid: 3.0.6 @@ -52,22 +52,22 @@ dependencies: # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.4.12 - test_core: 0.4.16 + test_api: 0.4.13 + test_core: 0.4.17 vm_service: 9.3.0 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - built_value: 8.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + built_value: 8.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 0.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - devtools_shared: 2.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + devtools_shared: 2.17.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,16 +91,16 @@ dependencies: dev_dependencies: collection: 1.16.0 file_testing: 3.0.0 - pubspec_parse: 1.2.0 + pubspec_parse: 1.2.1 checked_yaml: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.21.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.21.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 5a76 +# PUBSPEC CHECKSUM: 2f81 diff --git a/packages/flutter_tools/templates/app/lib/main.dart.tmpl b/packages/flutter_tools/templates/app/lib/main.dart.tmpl index 3062012e4767d..e963b8ac4afd5 100644 --- a/packages/flutter_tools/templates/app/lib/main.dart.tmpl +++ b/packages/flutter_tools/templates/app/lib/main.dart.tmpl @@ -112,7 +112,7 @@ class _MyHomePageState extends State { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/packages/flutter_tools/templates/app_shared/web/index.html.tmpl b/packages/flutter_tools/templates/app_shared/web/index.html.tmpl index 2ac781ff3b152..6d9aa4d08cc0c 100644 --- a/packages/flutter_tools/templates/app_shared/web/index.html.tmpl +++ b/packages/flutter_tools/templates/app_shared/web/index.html.tmpl @@ -46,11 +46,12 @@ _flutter.loader.loadEntrypoint({ serviceWorker: { serviceWorkerVersion: serviceWorkerVersion, + }, + onEntrypointLoaded: function(engineInitializer) { + engineInitializer.initializeEngine().then(function(appRunner) { + appRunner.runApp(); + }); } - }).then(function(engineInitializer) { - return engineInitializer.initializeEngine(); - }).then(function(appRunner) { - return appRunner.runApp(); }); }); diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/flutter_window.cpp b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/flutter_window.cpp index b43b9095ea3aa..b25e363efa423 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/flutter_window.cpp +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/flutter_window.cpp @@ -26,6 +26,11 @@ bool FlutterWindow::OnCreate() { } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + return true; } diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/main.cpp.tmpl b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/main.cpp.tmpl index e944ed007931e..70a53ab994df5 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/main.cpp.tmpl +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/main.cpp.tmpl @@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"{{projectName}}", origin, size)) { + if (!window.Create(L"{{projectName}}", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.cpp b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.cpp index 30b08cc8c9c5e..c7bcb4df4779c 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.cpp +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.cpp @@ -102,9 +102,9 @@ Win32Window::~Win32Window() { Destroy(); } -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { Destroy(); const wchar_t* window_class = @@ -117,7 +117,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); @@ -129,6 +129,10 @@ bool Win32Window::CreateAndShow(const std::wstring& title, return OnCreate(); } +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.h b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.h index 17ba431125b4b..a4b8f1f0ef8ea 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.h +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/runner/win32_window.h @@ -28,15 +28,16 @@ class Win32Window { Win32Window(); virtual ~Win32Window(); - // Creates and shows a win32 window with |title| and position and size using + // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); // Release OS resources associated with window. void Destroy(); diff --git a/packages/flutter_tools/templates/module/common/lib/main.dart.tmpl b/packages/flutter_tools/templates/module/common/lib/main.dart.tmpl index 51b5654e376b8..8c5545e059055 100644 --- a/packages/flutter_tools/templates/module/common/lib/main.dart.tmpl +++ b/packages/flutter_tools/templates/module/common/lib/main.dart.tmpl @@ -104,7 +104,7 @@ class _MyHomePageState extends State { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl b/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl index 7ea6b0e567c77..df5ad09c013c2 100644 --- a/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl @@ -24,7 +24,7 @@ dependencies: dev_dependencies: {{#withFfiPluginHook}} ffi: ^2.0.1 - ffigen: ^6.0.1 + ffigen: ^6.1.2 {{/withFfiPluginHook}} flutter_test: sdk: flutter diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart index 0205a9a723d92..2322d70d26a24 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:fake_async/fake_async.dart'; @@ -32,13 +30,12 @@ void main() { Cache.flutterRoot = getFlutterRoot(); }); - AnalysisServer server; - Directory tempDir; - FileSystem fileSystem; - Platform platform; - ProcessManager processManager; - AnsiTerminal terminal; - Logger logger; + late Directory tempDir; + late FileSystem fileSystem; + late Platform platform; + late ProcessManager processManager; + late AnsiTerminal terminal; + late Logger logger; setUp(() { fileSystem = globals.localFileSystem; @@ -51,7 +48,6 @@ void main() { tearDown(() { tryToDelete(tempDir); - return server?.dispose(); }); @@ -88,11 +84,10 @@ void main() { await pub.get( context: PubContext.flutterTests, directory: tempDir.path, - generateSyntheticPackage: false, ); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, [tempDir.path], fileSystem: fileSystem, platform: platform, @@ -109,6 +104,8 @@ void main() { await onDone; expect(errorCount, 0); + + await server.dispose(); }); }); @@ -126,18 +123,17 @@ void main() { await pub.get( context: PubContext.flutterTests, directory: tempDir.path, - generateSyntheticPackage: false, ); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, - [tempDir.path], - fileSystem: fileSystem, - platform: platform, - processManager: processManager, - logger: logger, - terminal: terminal, - ); + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, + [tempDir.path], + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + logger: logger, + terminal: terminal, + ); int errorCount = 0; final Future onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first; @@ -149,13 +145,15 @@ void main() { await onDone; expect(errorCount, greaterThan(0)); + + await server.dispose(); }); testUsingContext('Returns no errors when source is error-free', () async { const String contents = "StringBuffer bar = StringBuffer('baz');"; tempDir.childFile('main.dart').writeAsStringSync(contents); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, [tempDir.path], fileSystem: fileSystem, platform: platform, @@ -172,6 +170,7 @@ void main() { await server.start(); await onDone; expect(errorCount, 0); + await server.dispose(); }); testUsingContext('Can run AnalysisService with customized cache location', () async { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart index 1411060073e2d..172b0511f3c0d 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; @@ -22,7 +20,7 @@ import '../../src/test_flutter_command_runner.dart'; class ProjectValidatorDummy extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ return [ const ProjectValidatorResult(name: 'pass', value: 'value', status: StatusProjectValidator.success), const ProjectValidatorResult(name: 'fail', value: 'my error', status: StatusProjectValidator.error), @@ -41,7 +39,7 @@ class ProjectValidatorDummy extends ProjectValidator { class ProjectValidatorSecondDummy extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ return [ const ProjectValidatorResult(name: 'second', value: 'pass', status: StatusProjectValidator.success), const ProjectValidatorResult(name: 'other fail', value: 'second fail', status: StatusProjectValidator.error), @@ -59,7 +57,7 @@ class ProjectValidatorSecondDummy extends ProjectValidator { class ProjectValidatorCrash extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ throw Exception('my exception'); } @@ -73,10 +71,10 @@ class ProjectValidatorCrash extends ProjectValidator { } void main() { - FileSystem fileSystem; - Terminal terminal; - ProcessManager processManager; - Platform platform; + late FileSystem fileSystem; + late Terminal terminal; + late ProcessManager processManager; + late Platform platform; group('analyze --suggestions command', () { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart index b8424914fecd3..2dac6cf3bea28 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; @@ -46,13 +44,13 @@ void main() { }); group('analyze command', () { - FileSystem fileSystem; - Platform platform; - BufferLogger logger; - FakeProcessManager processManager; - Terminal terminal; - AnalyzeCommand command; - CommandRunner runner; + late FileSystem fileSystem; + late Platform platform; + late BufferLogger logger; + late FakeProcessManager processManager; + late Terminal terminal; + late AnalyzeCommand command; + late CommandRunner runner; setUpAll(() { Cache.disableLocking(); @@ -130,8 +128,8 @@ void main() { // Absolute paths expect(inRepo([tempDir.path], fileSystem), isFalse); expect(inRepo([fileSystem.path.join(tempDir.path, 'foo')], fileSystem), isFalse); - expect(inRepo([Cache.flutterRoot], fileSystem), isTrue); - expect(inRepo([fileSystem.path.join(Cache.flutterRoot, 'foo')], fileSystem), isTrue); + expect(inRepo([Cache.flutterRoot!], fileSystem), isTrue); + expect(inRepo([fileSystem.path.join(Cache.flutterRoot!, 'foo')], fileSystem), isTrue); // Relative paths fileSystem.currentDirectory = Cache.flutterRoot; @@ -158,6 +156,7 @@ void main() { 'startColumn': 4, }, 'message': 'Prefer final for variable declarations if they are not reassigned.', + 'code': 'var foo = 123;', 'hasFix': false, }; expect(WrittenError.fromJson(json).toString(), @@ -165,11 +164,11 @@ void main() { }); } -bool inRepo(List fileList, FileSystem fileSystem) { +bool inRepo(List? fileList, FileSystem fileSystem) { if (fileList == null || fileList.isEmpty) { fileList = [fileSystem.path.current]; } - final String root = fileSystem.path.normalize(fileSystem.path.absolute(Cache.flutterRoot)); + final String root = fileSystem.path.normalize(fileSystem.path.absolute(Cache.flutterRoot!)); final String prefix = root + fileSystem.path.separator; for (String file in fileList) { file = fileSystem.path.normalize(fileSystem.path.absolute(file)); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart index beb713cde5d58..072015afb1532 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart index c1047888865af..b830640caf280 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -21,9 +19,9 @@ import '../../src/fakes.dart'; import '../../src/test_build_system.dart'; void main() { - MemoryFileSystem memoryFileSystem; - Directory outputDirectory; - FakePlatform fakePlatform; + late MemoryFileSystem memoryFileSystem; + late Directory outputDirectory; + late FakePlatform fakePlatform; setUpAll(() { Cache.disableLocking(); @@ -48,7 +46,7 @@ void main() { group('build ios-framework', () { group('podspec', () { const String engineRevision = '0123456789abcdef'; - Cache cache; + late Cache cache; setUp(() { final Directory rootOverride = memoryFileSystem.directory('cache'); @@ -181,7 +179,7 @@ void main() { }); group('not on master channel', () { - FakeFlutterVersion fakeFlutterVersion; + late FakeFlutterVersion fakeFlutterVersion; setUp(() { const GitTagVersion gitTagVersion = GitTagVersion( x: 1, @@ -277,7 +275,7 @@ void main() { group('build macos-framework', () { group('podspec', () { const String engineRevision = '0123456789abcdef'; - Cache cache; + late Cache cache; setUp(() { final Directory rootOverride = memoryFileSystem.directory('cache'); @@ -410,7 +408,7 @@ void main() { }); group('not on master channel', () { - FakeFlutterVersion fakeFlutterVersion; + late FakeFlutterVersion fakeFlutterVersion; setUp(() { const GitTagVersion gitTagVersion = GitTagVersion( x: 1, @@ -504,8 +502,8 @@ void main() { }); group('XCFrameworks', () { - MemoryFileSystem fileSystem; - FakeProcessManager fakeProcessManager; + late MemoryFileSystem fileSystem; + late FakeProcessManager fakeProcessManager; setUp(() { fileSystem = MemoryFileSystem.test(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index d18c63bc22e76..a9dafa324d87a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -28,21 +26,21 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter @override Future> getBuildSettings( String projectPath, { - XcodeProjectBuildContext buildContext, + XcodeProjectBuildContext? buildContext, Duration timeout = const Duration(minutes: 1), }) async { return { 'PRODUCT_BUNDLE_IDENTIFIER': productBundleIdentifier ?? 'io.flutter.someProject', 'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos', 'WRAPPER_NAME': 'Runner.app', - if (developmentTeam != null) 'DEVELOPMENT_TEAM': developmentTeam, + if (developmentTeam != null) 'DEVELOPMENT_TEAM': developmentTeam!, }; } /// The value of 'PRODUCT_BUNDLE_IDENTIFIER'. - final String productBundleIdentifier; + final String? productBundleIdentifier; - final String developmentTeam; + final String? developmentTeam; } final Platform macosPlatform = FakePlatform( @@ -59,8 +57,8 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; + late FileSystem fileSystem; + late TestUsage usage; setUpAll(() { Cache.disableLocking(); @@ -90,7 +88,7 @@ void main() { 'xattr', '-r', '-d', 'com.apple.FinderInfo', '/', ]); - FakeCommand setUpRsyncCommand({void Function() onRun}) { + FakeCommand setUpRsyncCommand({void Function()? onRun}) { return FakeCommand( command: const [ 'rsync', @@ -104,7 +102,7 @@ void main() { ); } - FakeCommand setUpXCResultCommand({String stdout = '', void Function() onRun}) { + FakeCommand setUpXCResultCommand({String stdout = '', void Function()? onRun}) { return FakeCommand( command: const [ 'xcrun', @@ -125,10 +123,10 @@ void main() { FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, - String deviceId, + String? deviceId, int exitCode = 0, - String stdout, - void Function() onRun, + String? stdout, + void Function()? onRun, }) { return FakeCommand( command: [ diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 85630849f44b3..4599e7f55fc89 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -28,7 +26,7 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter @override Future> getBuildSettings( String projectPath, { - XcodeProjectBuildContext buildContext, + XcodeProjectBuildContext? buildContext, Duration timeout = const Duration(minutes: 1), }) async { return { @@ -53,9 +51,9 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; - FakeProcessManager fakeProcessManager; + late FileSystem fileSystem; + late TestUsage usage; + late FakeProcessManager fakeProcessManager; setUpAll(() { Cache.disableLocking(); @@ -86,7 +84,7 @@ void main() { 'xattr', '-r', '-d', 'com.apple.FinderInfo', '/', ]); - FakeCommand setUpXCResultCommand({String stdout = '', void Function() onRun}) { + FakeCommand setUpXCResultCommand({String stdout = '', void Function()? onRun}) { return FakeCommand( command: const [ 'xcrun', @@ -104,7 +102,7 @@ void main() { // Creates a FakeCommand for the xcodebuild call to build the app // in the given configuration. - FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, int exitCode = 0, void Function() onRun }) { + FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, int exitCode = 0, void Function()? onRun }) { return FakeCommand( command: [ 'xcrun', @@ -134,7 +132,7 @@ void main() { FakeCommand exportArchiveCommand({ String exportOptionsPlist = '/ExportOptions.plist', - File cachePlist, + File? cachePlist, }) { return FakeCommand( command: [ diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart index bf8d2db8f4166..363dfcdf366fd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; @@ -45,9 +43,9 @@ void main() { Cache.disableLocking(); }); - FileSystem fileSystem; - ProcessManager processManager; - TestUsage usage; + late FileSystem fileSystem; + late ProcessManager processManager; + late TestUsage usage; setUp(() { fileSystem = MemoryFileSystem.test(); @@ -71,7 +69,7 @@ void main() { // Returns the command matching the build_linux call to cmake. FakeCommand cmakeCommand(String buildMode, { String target = 'x64', - void Function() onRun, + void Function()? onRun, }) { return FakeCommand( command: [ @@ -89,9 +87,9 @@ void main() { // Returns the command matching the build_linux call to ninja. FakeCommand ninjaCommand(String buildMode, { - Map environment, + Map? environment, String target = 'x64', - void Function() onRun, + void Function()? onRun, String stdout = '', }) { return FakeCommand( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart index 245ed862bd810..acab399a12f6e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:args/command_runner.dart'; @@ -29,7 +27,7 @@ import '../../src/test_flutter_command_runner.dart'; class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter { @override - Future getInfo(String projectPath, { String projectFilename }) async { + Future getInfo(String projectPath, { String? projectFilename }) async { return XcodeProjectInfo( ['Runner'], ['Debug', 'Profile', 'Release'], @@ -62,10 +60,10 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; - FakeProcessManager fakeProcessManager; - XcodeProjectInterpreter xcodeProjectInterpreter; + late FileSystem fileSystem; + late TestUsage usage; + late FakeProcessManager fakeProcessManager; + late XcodeProjectInterpreter xcodeProjectInterpreter; setUpAll(() { Cache.disableLocking(); @@ -93,7 +91,7 @@ void main() { // Creates a FakeCommand for the xcodebuild call to build the app // in the given configuration. - FakeCommand setUpFakeXcodeBuildHandler(String configuration, { bool verbose = false, void Function() onRun }) { + FakeCommand setUpFakeXcodeBuildHandler(String configuration, { bool verbose = false, void Function()? onRun }) { final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory()); return FakeCommand( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart index 57aba7ecd519b..144ed0e1094cf 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -27,8 +25,8 @@ void main() { 'combination with "--${FlutterOptions.kSplitDebugInfoOption}"')); }); group('Fatal Logs', () { - FakeBuildCommand command; - MemoryFileSystem fs; + late FakeBuildCommand command; + late MemoryFileSystem fs; setUp(() { fs = MemoryFileSystem.test(); @@ -134,7 +132,7 @@ class FakeBuildCommand extends BuildCommand { } class FakeBuildSubcommand extends BuildSubCommand { - FakeBuildSubcommand({@required bool verboseHelp}) : super(verboseHelp: verboseHelp); + FakeBuildSubcommand({required super.verboseHelp}); @override String get description => ''; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 3dd5335de24b1..77aeb4888eb9e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -23,7 +21,7 @@ import '../../src/test_build_system.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; + late FileSystem fileSystem; final Platform fakePlatform = FakePlatform( environment: { 'FLUTTER_ROOT': '/', @@ -243,7 +241,7 @@ class TestWebBuildCommand extends FlutterCommand { final String description = 'Build a test executable app.'; @override - Future runCommand() async => null; + Future runCommand() async => FlutterCommandResult.fail(); @override bool get shouldRunPub => false; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index f702f87980ce8..469555a301024 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -43,10 +41,9 @@ final Platform notWindowsPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - - ProcessManager processManager; - TestUsage usage; + late FileSystem fileSystem; + late ProcessManager processManager; + late TestUsage usage; setUpAll(() { Cache.disableLocking(); @@ -75,7 +72,7 @@ void main() { // Returns the command matching the build_windows call to generate CMake // files. FakeCommand cmakeGenerationCommand({ - void Function() onRun, + void Function()? onRun, String generator = _defaultGenerator, }) { return FakeCommand( @@ -95,7 +92,7 @@ void main() { // Returns the command matching the build_windows call to build. FakeCommand buildCommand(String buildMode, { bool verbose = false, - void Function() onRun, + void Function()? onRun, String stdout = '', }) { return FakeCommand( @@ -974,7 +971,7 @@ class FakeVisualStudio extends Fake implements VisualStudio { }); @override - final String cmakePath; + final String? cmakePath; @override final String cmakeGenerator; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 523c3b2defd37..6cc52e3230972 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -28,13 +26,13 @@ class FakePub extends Fake implements Pub { @override Future get({ - PubContext context, - String directory, + PubContext? context, + String? directory, bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, - String flutterRootOverride, + String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, @@ -50,8 +48,8 @@ class FakePub extends Fake implements Pub { void main() { group('usageValues', () { - Testbed testbed; - FakePub fakePub; + late Testbed testbed; + late FakePub fakePub; setUpAll(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart index 3a3f057c0143c..1d23c9872e454 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:typed_data'; @@ -23,7 +21,6 @@ import 'package:flutter_tools/src/commands/custom_devices.dart'; import 'package:flutter_tools/src/custom_devices/custom_device_config.dart'; import 'package:flutter_tools/src/custom_devices/custom_devices_config.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -171,7 +168,7 @@ final Platform windowsPlatform = FakePlatform( ); class FakeTerminal implements Terminal { - factory FakeTerminal({Platform platform}) { + factory FakeTerminal({required Platform platform}) { return FakeTerminal._private( stdio: FakeStdio(), platform: platform @@ -179,8 +176,8 @@ class FakeTerminal implements Terminal { } FakeTerminal._private({ - this.stdio, - Platform platform + required this.stdio, + required Platform platform }) : terminal = AnsiTerminal( stdio: stdio, @@ -215,9 +212,9 @@ class FakeTerminal implements Terminal { @override Future promptForCharInput( List acceptedCharacters, { - Logger logger, - String prompt, - int defaultChoiceIndex, + required Logger logger, + String? prompt, + int? defaultChoiceIndex, bool displayAcceptedCharacters = true }) => terminal.promptForCharInput( acceptedCharacters, @@ -253,10 +250,10 @@ class FakeTerminal implements Terminal { class FakeCommandRunner extends FlutterCommandRunner { FakeCommandRunner({ - @required Platform platform, - @required FileSystem fileSystem, - @required Logger logger, - UserMessages userMessages + required Platform platform, + required FileSystem fileSystem, + required Logger logger, + UserMessages? userMessages }) : _platform = platform, _fileSystem = fileSystem, _logger = logger, @@ -285,7 +282,7 @@ class FakeCommandRunner extends FlutterCommandRunner { userMessages: _userMessages, ); // For compatibility with tests that set this to a relative path. - Cache.flutterRoot = _fileSystem.path.normalize(_fileSystem.path.absolute(Cache.flutterRoot)); + Cache.flutterRoot = _fileSystem.path.normalize(_fileSystem.path.absolute(Cache.flutterRoot!)); return super.runCommand(topLevelResults); } ); @@ -295,13 +292,13 @@ class FakeCommandRunner extends FlutterCommandRunner { /// May take platform, logger, processManager and fileSystem from context if /// not explicitly specified. CustomDevicesCommand createCustomDevicesCommand({ - CustomDevicesConfig Function(FileSystem, Logger) config, - Terminal Function(Platform) terminal, - Platform platform, - FileSystem fileSystem, - ProcessManager processManager, - Logger logger, - PrintFn usagePrintFn, + CustomDevicesConfig Function(FileSystem, Logger)? config, + Terminal Function(Platform)? terminal, + Platform? platform, + FileSystem? fileSystem, + ProcessManager? processManager, + Logger? logger, + PrintFn? usagePrintFn, bool featureEnabled = false }) { platform ??= FakePlatform(); @@ -340,13 +337,13 @@ CustomDevicesCommand createCustomDevicesCommand({ /// May take platform, logger, processManager and fileSystem from context if /// not explicitly specified. CommandRunner createCustomDevicesCommandRunner({ - CustomDevicesConfig Function(FileSystem, Logger) config, - Terminal Function(Platform) terminal, - Platform platform, - FileSystem fileSystem, - ProcessManager processManager, - Logger logger, - PrintFn usagePrintFn, + CustomDevicesConfig Function(FileSystem, Logger)? config, + Terminal Function(Platform)? terminal, + Platform? platform, + FileSystem? fileSystem, + ProcessManager? processManager, + Logger? logger, + PrintFn? usagePrintFn, bool featureEnabled = false, }) { platform ??= FakePlatform(); @@ -372,17 +369,17 @@ CommandRunner createCustomDevicesCommandRunner({ } FakeTerminal createFakeTerminalForAddingSshDevice({ - @required Platform platform, - @required String id, - @required String label, - @required String sdkNameAndVersion, - @required String enabled, - @required String hostname, - @required String username, - @required String runDebug, - @required String usePortForwarding, - @required String screenshot, - @required String apply + required Platform platform, + required String id, + required String label, + required String sdkNameAndVersion, + required String enabled, + required String hostname, + required String username, + required String runDebug, + required String usePortForwarding, + required String screenshot, + required String apply }) { return FakeTerminal(platform: platform) ..simulateStdin(id) diff --git a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart index 71cfa5b4a1861..a03cf8bc4acb2 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:io' as io; import 'dart:typed_data'; @@ -57,7 +55,7 @@ class FakeDaemonStreams implements DaemonStreams { } @override - void send(Map message, [ List binary ]) { + void send(Map message, [ List? binary ]) { outputs.add(DaemonMessage(message, binary != null ? Stream>.value(binary) : null)); } @@ -70,12 +68,12 @@ class FakeDaemonStreams implements DaemonStreams { } void main() { - Daemon daemon; - NotifyingLogger notifyingLogger; + late Daemon daemon; + late NotifyingLogger notifyingLogger; group('daemon', () { - FakeDaemonStreams daemonStreams; - DaemonConnection daemonConnection; + late FakeDaemonStreams daemonStreams; + late DaemonConnection daemonConnection; setUp(() { BufferLogger bufferLogger; bufferLogger = BufferLogger.test(); @@ -100,7 +98,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.version'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.version'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isNotEmpty); @@ -115,7 +113,7 @@ void main() { // Use the flutter_gallery project which has a known set of supported platforms. final String projectPath = globals.fs.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'flutter_gallery'); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': {'projectRoot': projectPath}, @@ -124,7 +122,7 @@ void main() { expect(response.data['id'], 0); expect(response.data['result'], isNotEmpty); - expect((response.data['result'] as Map)['platforms'], {'macos'}); + expect((response.data['result']! as Map)['platforms'], {'macos'}); }, overrides: { // Disable Android/iOS and enable macOS to make sure result is consistent and defaults are tested off. FeatureFlags: () => TestFeatureFlags(isAndroidEnabled: false, isIOSEnabled: false, isMacOSEnabled: true), @@ -137,11 +135,11 @@ void main() { ); globals.printError('daemon.logMessage test'); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage message) { - return message.data['event'] == 'daemon.logMessage' && (message.data['params'] as Map)['level'] == 'error'; + return message.data['event'] == 'daemon.logMessage' && (message.data['params']! as Map)['level'] == 'error'; }); expect(response.data['id'], isNull); expect(response.data['event'], 'daemon.logMessage'); - final Map logMessage = castStringKeyedMap(response.data['params']).cast(); + final Map logMessage = castStringKeyedMap(response.data['params'])!.cast(); expect(logMessage['level'], 'error'); expect(logMessage['message'], 'daemon.logMessage test'); }, overrides: { @@ -155,11 +153,11 @@ void main() { ); globals.printWarning('daemon.logMessage test'); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage message) { - return message.data['event'] == 'daemon.logMessage' && (message.data['params'] as Map)['level'] == 'warning'; + return message.data['event'] == 'daemon.logMessage' && (message.data['params']! as Map)['level'] == 'warning'; }); expect(response.data['id'], isNull); expect(response.data['event'], 'daemon.logMessage'); - final Map logMessage = castStringKeyedMap(response.data['params']).cast(); + final Map logMessage = castStringKeyedMap(response.data['params'])!.cast(); expect(logMessage['level'], 'warning'); expect(logMessage['message'], 'daemon.logMessage test'); }, overrides: { @@ -203,7 +201,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.shutdown'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.shutdown'})); return daemon.onExit.then((int code) async { await daemonStreams.inputs.close(); expect(code, 0); @@ -216,7 +214,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.restart'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.restart'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('appId is required')); @@ -228,7 +226,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'app.callServiceExtension', 'params': { @@ -246,7 +244,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.stop'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.stop'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('appId is required')); @@ -257,7 +255,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -271,10 +269,10 @@ void main() { final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, isList); expect(result, isNotEmpty); }); @@ -293,7 +291,7 @@ void main() { expect(response.data['event'], 'device.added'); expect(response.data['params'], isMap); - final Map params = castStringKeyedMap(response.data['params']); + final Map params = castStringKeyedMap(response.data['params'])!; expect(params['platform'], isNotEmpty); // the fake device has a platform of 'android-arm' }); }, overrides: { @@ -307,7 +305,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -321,10 +319,10 @@ void main() { final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, isList); expect(result, isNotEmpty); expect(discoverer.discoverDevicesCalled, true); @@ -339,17 +337,17 @@ void main() { daemon.deviceDomain.addDeviceDiscoverer(discoverer); final FakeAndroidDevice device = FakeAndroidDevice(); discoverer.addDevice(device); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.supportsRuntimeMode', - 'params': { + 'params': { 'deviceId': 'device', 'buildMode': 'profile', }, })); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, true); expect(device.supportsRuntimeModeCalledBuildMode, BuildMode.profile); }); @@ -365,17 +363,17 @@ void main() { discoverer.addDevice(device); final FakeDeviceLogReader logReader = FakeDeviceLogReader(); device.logReader = logReader; - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.logReader.start', - 'params': { + 'params': { 'deviceId': 'device', }, })); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); expect(firstResponse.data['id'], 0); - final String logReaderId = firstResponse.data['result'] as String; + final String? logReaderId = firstResponse.data['result'] as String?; expect(logReaderId, isNotNull); // Try sending logs. @@ -387,10 +385,10 @@ void main() { // Now try to stop the log reader. expect(logReader.disposeCalled, false); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 1, 'method': 'device.logReader.stop', - 'params': { + 'params': { 'id': logReaderId, }, })); @@ -400,7 +398,7 @@ void main() { }); group('device.startApp and .stopApp', () { - FakeApplicationPackageFactory applicationPackageFactory; + late FakeApplicationPackageFactory applicationPackageFactory; setUp(() { applicationPackageFactory = FakeApplicationPackageFactory(); }); @@ -419,27 +417,27 @@ void main() { // First upload the application package. final FakeApplicationPackage applicationPackage = FakeApplicationPackage(); applicationPackageFactory.applicationPackage = applicationPackage; - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.uploadApplicationPackage', - 'params': { + 'params': { 'targetPlatform': 'android', 'applicationBinary': 'test_file', }, })); final DaemonMessage applicationPackageIdResponse = await broadcastOutput.firstWhere(_notEvent); expect(applicationPackageIdResponse.data['id'], 0); - expect(applicationPackageFactory.applicationBinaryRequested.basename, 'test_file'); + expect(applicationPackageFactory.applicationBinaryRequested!.basename, 'test_file'); expect(applicationPackageFactory.platformRequested, TargetPlatform.android); - final String applicationPackageId = applicationPackageIdResponse.data['result'] as String; + final String? applicationPackageId = applicationPackageIdResponse.data['result'] as String?; // Try starting the app. final Uri observatoryUri = Uri.parse('http://127.0.0.1:12345/observatory'); device.launchResult = LaunchResult.succeeded(observatoryUri: observatoryUri); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 1, 'method': 'device.startApp', - 'params': { + 'params': { 'deviceId': 'device', 'applicationPackageId': applicationPackageId, 'debuggingOptions': DebuggingOptions.enabled(BuildInfo.debug).toJson(), @@ -448,15 +446,15 @@ void main() { final DaemonMessage startAppResponse = await broadcastOutput.firstWhere(_notEvent); expect(startAppResponse.data['id'], 1); expect(device.startAppPackage, applicationPackage); - final Map startAppResult = startAppResponse.data['result'] as Map; + final Map startAppResult = startAppResponse.data['result']! as Map; expect(startAppResult['started'], true); expect(startAppResult['observatoryUri'], observatoryUri.toString()); // Try stopping the app. - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 2, 'method': 'device.stopApp', - 'params': { + 'params': { 'deviceId': 'device', 'applicationPackageId': applicationPackageId, }, @@ -464,7 +462,7 @@ void main() { final DaemonMessage stopAppResponse = await broadcastOutput.firstWhere(_notEvent); expect(stopAppResponse.data['id'], 2); expect(device.stopAppPackage, applicationPackage); - final bool stopAppResult = stopAppResponse.data['result'] as bool; + final bool? stopAppResult = stopAppResponse.data['result'] as bool?; expect(stopAppResult, true); }, overrides: { ApplicationPackageFactory: () => applicationPackageFactory, @@ -477,7 +475,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('emulatorId is required')); @@ -488,8 +486,8 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - final Map params = {'emulatorId': 'device', 'coldBoot': 1}; - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch', 'params': params})); + final Map params = {'emulatorId': 'device', 'coldBoot': 1}; + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch', 'params': params})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('coldBoot is not a bool')); @@ -500,7 +498,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.getEmulators'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.getEmulators'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -519,8 +517,8 @@ void main() { unawaited(daemonStreams.outputs.stream .firstWhere((DaemonMessage request) => request.data['method'] == 'app.exposeUrl') .then((DaemonMessage request) { - expect((request.data['params'] as Map)['url'], equals(originalUrl)); - daemonStreams.inputs.add(DaemonMessage({'id': request.data['id'], 'result': {'url': mappedUrl}})); + expect((request.data['params']! as Map)['url'], equals(originalUrl)); + daemonStreams.inputs.add(DaemonMessage({'id': request.data['id'], 'result': {'url': mappedUrl}})); }) ); @@ -534,9 +532,9 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage response) => response.data['id'] == 0); - final Map result = response.data['result'] as Map; + final Map result = response.data['result']! as Map; expect(result, isNotEmpty); expect(result['host'], '127.0.0.1'); expect(result['port'], 1234); @@ -550,9 +548,9 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage response) => response.data['id'] == 0); - final Map result = response.data['result'] as Map; + final Map result = response.data['result']! as Map; expect(result, isNotEmpty); expect(result['host'], null); expect(result['port'], null); @@ -565,8 +563,8 @@ void main() { await io.IOOverrides.runWithIOOverrides(() async { final FakeSocket socket = FakeSocket(); bool connectCalled = false; - int connectPort; - ioOverrides.connectCallback = (dynamic host, int port) async { + int? connectPort; + ioOverrides.connectCallback = (Object? host, int port) async { connectCalled = true; connectPort = port; if (host == io.InternetAddress.loopbackIPv4) { @@ -579,7 +577,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -588,7 +586,7 @@ void main() { expect(connectCalled, true); expect(connectPort, 123); - final Object id = firstResponse.data['result']; + final Object? id = firstResponse.data['result']; // Can send received data as event. socket.controller.add(Uint8List.fromList([10, 11, 12])); @@ -596,22 +594,22 @@ void main() { (DaemonMessage message) => message.data['event'] != null && message.data['event'] == 'proxy.data.$id', ); expect(dataEvent.binary, isNotNull); - final List> data = await dataEvent.binary.toList(); + final List> data = await dataEvent.binary!.toList(); expect(data[0], [10, 11, 12]); // Can proxy data to the socket. - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.write', 'params': {'id': id}}, Stream>.value([21, 22, 23]))); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.write', 'params': {'id': id}}, Stream>.value([21, 22, 23]))); await pumpEventQueue(); expect(socket.addedData[0], [21, 22, 23]); // Closes the connection when disconnect request received. expect(socket.closeCalled, false); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.disconnect', 'params': {'id': id}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.disconnect', 'params': {'id': id}})); await pumpEventQueue(); expect(socket.closeCalled, true); // Sends disconnected event when socket.done completer finishes. - socket.doneCompleter.complete(); + socket.doneCompleter.complete(true); final DaemonMessage disconnectEvent = await broadcastOutput.firstWhere( (DaemonMessage message) => message.data['event'] != null && message.data['event'] == 'proxy.disconnected.$id', ); @@ -624,8 +622,8 @@ void main() { await io.IOOverrides.runWithIOOverrides(() async { final FakeSocket socket = FakeSocket(); bool connectIpv4Called = false; - int connectPort; - ioOverrides.connectCallback = (dynamic host, int port) async { + int? connectPort; + ioOverrides.connectCallback = (Object? host, int port) async { connectPort = port; if (host == io.InternetAddress.loopbackIPv4) { connectIpv4Called = true; @@ -639,7 +637,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -653,13 +651,13 @@ void main() { testUsingContext('proxy.connect fails if both ipv6 and ipv4 failed', () async { final TestIOOverrides ioOverrides = TestIOOverrides(); await io.IOOverrides.runWithIOOverrides(() async { - ioOverrides.connectCallback = (dynamic host, int port) => throw const io.SocketException('fail'); + ioOverrides.connectCallback = (Object? host, int port) => throw const io.SocketException('fail'); daemon = Daemon( daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -671,7 +669,7 @@ void main() { }); group('notifyingLogger', () { - BufferLogger bufferLogger; + late BufferLogger bufferLogger; setUp(() { bufferLogger = BufferLogger.test(); }); @@ -713,7 +711,7 @@ void main() { }); group('daemon queue', () { - DebounceOperationQueue queue; + late DebounceOperationQueue queue; const Duration debounceDuration = Duration(seconds: 1); setUp(() { @@ -741,7 +739,7 @@ void main() { await _runFakeAsync((FakeAsync time) async { final List> operations = >[ queue.queueAndDebounce('OP1', debounceDuration, () async => 1), - Future.delayed(debounceDuration * 2).then((_) => + Future.delayed(debounceDuration * 2).then((_) => queue.queueAndDebounce('OP1', debounceDuration, () async => 2)), ]; @@ -873,42 +871,42 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override bool get supportsStartPaused => true; - BuildMode supportsRuntimeModeCalledBuildMode; + BuildMode? supportsRuntimeModeCalledBuildMode; @override Future supportsRuntimeMode(BuildMode buildMode) async { supportsRuntimeModeCalledBuildMode = buildMode; return true; } - DeviceLogReader logReader; + late DeviceLogReader logReader; @override FutureOr getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) => logReader; - ApplicationPackage startAppPackage; - LaunchResult launchResult; + ApplicationPackage? startAppPackage; + late LaunchResult launchResult; @override Future startApp( ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs = const {}, + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { startAppPackage = package; return launchResult; } - ApplicationPackage stopAppPackage; + ApplicationPackage? stopAppPackage; @override Future stopApp( ApplicationPackage app, { - String userIdentifier, + String? userIdentifier, }) async { stopAppPackage = app; return true; @@ -920,10 +918,10 @@ class FakeDeviceLogReader implements DeviceLogReader { bool disposeCalled = false; @override - int appPid; + int? appPid; @override - FlutterVmService connectedVMService; + FlutterVmService? connectedVMService; @override void dispose() { @@ -941,22 +939,22 @@ class FakeDeviceLogReader implements DeviceLogReader { class FakeDevtoolsLauncher extends Fake implements DevtoolsLauncher { FakeDevtoolsLauncher(this._serverAddress); - final DevToolsServerAddress _serverAddress; + final DevToolsServerAddress? _serverAddress; @override - Future serve() async => _serverAddress; + Future serve() async => _serverAddress; @override Future close() async {} } class FakeApplicationPackageFactory implements ApplicationPackageFactory { - TargetPlatform platformRequested; - File applicationBinaryRequested; - ApplicationPackage applicationPackage; + TargetPlatform? platformRequested; + File? applicationBinaryRequested; + ApplicationPackage? applicationPackage; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { platformRequested = platform; applicationBinaryRequested = applicationBinary; return applicationPackage; @@ -966,11 +964,11 @@ class FakeApplicationPackageFactory implements ApplicationPackageFactory { class FakeApplicationPackage extends Fake implements ApplicationPackage {} class TestIOOverrides extends io.IOOverrides { - Future Function(dynamic host, int port) connectCallback; + late Future Function(Object? host, int port) connectCallback; @override - Future socketConnect(dynamic host, int port, - {dynamic sourceAddress, int sourcePort = 0, Duration timeout}) { + Future socketConnect(Object? host, int port, + {Object? sourceAddress, int sourcePort = 0, Duration? timeout}) { return connectCallback(host, port); } } @@ -983,10 +981,10 @@ class FakeSocket extends Fake implements io.Socket { @override StreamSubscription listen( - void Function(Uint8List event) onData, { - Function onError, - void Function() onDone, - bool cancelOnError, + void Function(Uint8List event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, }) { return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart index ca3ffe87c21f8..46bfb7fbe4a9c 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:convert'; import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/devices.dart'; import 'package:flutter_tools/src/device.dart'; @@ -24,7 +24,7 @@ void main() { Cache.disableLocking(); }); - Cache cache; + late Cache cache; setUp(() { cache = Cache.test(processManager: FakeProcessManager.any()); @@ -52,7 +52,7 @@ void main() { testUsingContext("get devices' platform types", () async { final List platformTypes = Device.devicesPlatformTypes( - await globals.deviceManager.getAllConnectedDevices(), + await globals.deviceManager!.getAllConnectedDevices(), ); expect(platformTypes, ['android', 'web']); }, overrides: { @@ -133,14 +133,14 @@ webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulato } class _FakeDeviceManager extends DeviceManager { - _FakeDeviceManager(); + _FakeDeviceManager() : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); @override Future> getAllConnectedDevices() => Future>.value(fakeDevices.map((FakeDeviceJsonData d) => d.dev).toList()); @override - Future> refreshAllConnectedDevices({Duration timeout}) => + Future> refreshAllConnectedDevices({Duration? timeout}) => getAllConnectedDevices(); @override @@ -153,11 +153,13 @@ class _FakeDeviceManager extends DeviceManager { } class NoDevicesManager extends DeviceManager { + NoDevicesManager() : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); + @override Future> getAllConnectedDevices() async => []; @override - Future> refreshAllConnectedDevices({Duration timeout}) => + Future> refreshAllConnectedDevices({Duration? timeout}) => getAllConnectedDevices(); @override diff --git a/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart index a2ad7121d0a8d..90b2e6ee3c0ee 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/io.dart'; @@ -20,11 +18,11 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger bufferLogger; - FakeTerminal terminal; - ProcessManager processManager; - FakeStdio stdio; + late FileSystem fileSystem; + late BufferLogger bufferLogger; + late FakeTerminal terminal; + late ProcessManager processManager; + late FakeStdio stdio; setUpAll(() { Cache.disableLocking(); @@ -224,11 +222,11 @@ class FakeTerminal extends Fake implements Terminal { _selected = selected; } - List _characters; - String _selected; + List? _characters; + late String _selected; @override - Future promptForCharInput(List acceptedCharacters, {Logger logger, String prompt, int defaultChoiceIndex, bool displayAcceptedCharacters = true}) async { + Future promptForCharInput(List acceptedCharacters, {Logger? logger, String? prompt, int? defaultChoiceIndex, bool displayAcceptedCharacters = true}) async { expect(acceptedCharacters, _characters); return _selected; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart index 4cdf7531f6c86..397b4a666ce39 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/base/common.dart'; @@ -25,10 +23,10 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - FakeDeviceManager fakeDeviceManager; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late FakeDeviceManager fakeDeviceManager; setUp(() { fileSystem = MemoryFileSystem.test(); @@ -254,15 +252,15 @@ void main() { class ThrowingScreenshotDevice extends ScreenshotDevice { @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map? platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { throwToolExit('cannot start app'); } @@ -289,15 +287,15 @@ class ScreenshotDevice extends Fake implements Device { @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map? platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async => LaunchResult.succeeded(); @override @@ -307,13 +305,13 @@ class ScreenshotDevice extends Fake implements Device { class FakePub extends Fake implements Pub { @override Future get({ - PubContext context, - String directory, + PubContext? context, + String? directory, bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, - String flutterRootOverride, + String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, @@ -324,13 +322,13 @@ class FakeDeviceManager extends Fake implements DeviceManager { List devices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override Future> getDevices() async => devices; @override - Future> findTargetDevices(FlutterProject flutterProject, {Duration timeout}) async => devices; + Future> findTargetDevices(FlutterProject? flutterProject, {Duration? timeout}) async => devices; } class FailingFakeFlutterDriverFactory extends Fake implements FlutterDriverFactory { @@ -348,13 +346,13 @@ class FailingFakeDriverService extends Fake implements DriverService { List arguments, Map environment, PackageConfig packageConfig, { - bool headless, - String chromeBinary, - String browserName, - bool androidEmulator, - int driverPort, - List webBrowserFlags, - List browserDimension, - String profileMemory, + bool? headless, + String? chromeBinary, + String? browserName, + bool? androidEmulator, + int? driverPort, + List? webBrowserFlags, + List? browserDimension, + String? profileMemory, }) async => 1; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index 89d19d532812a..c2507e71a5d80 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -2,22 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; +import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/generate_localizations.dart'; -import 'package:flutter_tools/src/runner/flutter_command.dart'; import '../../integration.shard/test_data/basic_project.dart'; import '../../src/common.dart'; import '../../src/context.dart'; +import '../../src/fake_process_manager.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; + late FileSystem fileSystem; + late BufferLogger logger; + late Artifacts artifacts; + late FakeProcessManager processManager; setUpAll(() { Cache.disableLocking(); @@ -25,10 +27,12 @@ void main() { setUp(() { fileSystem = MemoryFileSystem.test(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + processManager = FakeProcessManager.empty(); }); testUsingContext('default l10n settings', () async { - final BufferLogger logger = BufferLogger.test(); final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); arbFile.writeAsStringSync(''' @@ -41,11 +45,11 @@ void main() { final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, + artifacts: artifacts, + processManager: processManager, ); await createTestCommandRunner(command).run(['gen-l10n']); - final FlutterCommandResult result = await command.runCommand(); - expect(result.exitStatus, ExitStatus.success); final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n')); expect(outputDirectory.existsSync(), true); expect(outputDirectory.childFile('app_localizations_en.dart').existsSync(), true); @@ -56,7 +60,6 @@ void main() { }); testUsingContext('not using synthetic packages', () async { - final BufferLogger logger = BufferLogger.test(); final Directory l10nDirectory = fileSystem.directory( fileSystem.path.join('lib', 'l10n'), ); @@ -75,14 +78,14 @@ void main() { final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, + artifacts: artifacts, + processManager: processManager, ); await createTestCommandRunner(command).run([ 'gen-l10n', '--no-synthetic-package', ]); - final FlutterCommandResult result = await command.runCommand(); - expect(result.exitStatus, ExitStatus.success); expect(l10nDirectory.existsSync(), true); expect(l10nDirectory.childFile('app_localizations_en.dart').existsSync(), true); expect(l10nDirectory.childFile('app_localizations.dart').existsSync(), true); @@ -92,7 +95,6 @@ void main() { }); testUsingContext('throws error when arguments are invalid', () async { - final BufferLogger logger = BufferLogger.test(); final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); arbFile.writeAsStringSync(''' @@ -107,6 +109,8 @@ void main() { final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, + artifacts: artifacts, + processManager: processManager, ); expect( () => createTestCommandRunner(command).run([ @@ -122,7 +126,6 @@ void main() { }); testUsingContext('l10n yaml file takes precedence over command line arguments', () async { - final BufferLogger logger = BufferLogger.test(); final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); arbFile.writeAsStringSync(''' @@ -138,11 +141,11 @@ void main() { final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, + artifacts: artifacts, + processManager: processManager, ); await createTestCommandRunner(command).run(['gen-l10n']); - final FlutterCommandResult result = await command.runCommand(); - expect(result.exitStatus, ExitStatus.success); expect(logger.statusText, contains('Because l10n.yaml exists, the options defined there will be used instead.')); final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n')); expect(outputDirectory.existsSync(), true); @@ -154,7 +157,6 @@ void main() { }); testUsingContext('nullable-getter help message is expected string', () async { - final BufferLogger logger = BufferLogger.test(); final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); arbFile.writeAsStringSync(''' @@ -170,6 +172,8 @@ void main() { final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, + artifacts: artifacts, + processManager: processManager, ); await createTestCommandRunner(command).run(['gen-l10n']); expect(command.usage, contains(' If this value is set to false, then ')); @@ -177,4 +181,88 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), }); + + testUsingContext('dart format is run when --format is passed', () async { + final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) + ..createSync(recursive: true); + arbFile.writeAsStringSync(''' +{ + "helloWorld": "Hello, World!", + "@helloWorld": { + "description": "Sample description" + } +}'''); + processManager.addCommand( + const FakeCommand( + command: [ + 'HostArtifact.engineDartBinary', + 'format', + '/.dart_tool/flutter_gen/gen_l10n/app_localizations_en.dart', + '/.dart_tool/flutter_gen/gen_l10n/app_localizations.dart', + ] + ) + ); + + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + + await createTestCommandRunner(command).run(['gen-l10n', '--format']); + + final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n')); + expect(outputDirectory.existsSync(), true); + expect(outputDirectory.childFile('app_localizations_en.dart').existsSync(), true); + expect(outputDirectory.childFile('app_localizations.dart').existsSync(), true); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('dart format is run when format: true is passed into l10n.yaml', () async { + final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) + ..createSync(recursive: true); + arbFile.writeAsStringSync(''' +{ + "helloWorld": "Hello, World!", + "@helloWorld": { + "description": "Sample description" + } +}'''); + final File configFile = fileSystem.file('l10n.yaml')..createSync(); + configFile.writeAsStringSync(''' +format: true +'''); + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + pubspecFile.writeAsStringSync(BasicProjectWithFlutterGen().pubspec); + processManager.addCommand( + const FakeCommand( + command: [ + 'HostArtifact.engineDartBinary', + 'format', + '/.dart_tool/flutter_gen/gen_l10n/app_localizations_en.dart', + '/.dart_tool/flutter_gen/gen_l10n/app_localizations.dart', + ] + ) + ); + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + await createTestCommandRunner(command).run(['gen-l10n']); + + final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n')); + expect(outputDirectory.existsSync(), true); + expect(outputDirectory.childFile('app_localizations_en.dart').existsSync(), true); + expect(outputDirectory.childFile('app_localizations.dart').existsSync(), true); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart index dcd7c484ddaa4..1a544a787a209 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -17,12 +15,12 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('ide_config', () { - Directory tempDir; - Directory templateDir; - Directory intellijDir; - Directory toolsDir; + late Directory tempDir; + late Directory templateDir; + late Directory intellijDir; + late Directory toolsDir; - Map getFilesystemContents([ Directory root ]) { + Map getFilesystemContents([ Directory? root ]) { final String tempPath = tempDir.absolute.path; final List paths = (root ?? tempDir).listSync(recursive: true).map((FileSystemEntity entity) { @@ -67,7 +65,7 @@ void main() { if (manifest[key] != 'dir') { tempDir.childFile(key) ..createSync(recursive: true) - ..writeAsStringSync(manifest[key]); + ..writeAsStringSync(manifest[key]!); } } } @@ -78,7 +76,7 @@ void main() { } Future updateIdeConfig({ - Directory dir, + Directory? dir, List args = const [], Map expectedContents = const {}, List unexpectedPaths = const [], diff --git a/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart index 4504abd8d1035..54810d871145b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/android/android_device.dart'; @@ -27,7 +25,7 @@ void main() { Cache.disableLocking(); }); - FileSystem fileSystem; + late FileSystem fileSystem; setUp(() { fileSystem = MemoryFileSystem.test(); fileSystem.file('pubspec.yaml').createSync(recursive: true); @@ -114,7 +112,7 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFa final ApplicationPackage app; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { return app; } } @@ -131,13 +129,13 @@ class FakeIOSDevice extends Fake implements IOSDevice { @override Future isAppInstalled( IOSApp app, { - String userIdentifier, + String? userIdentifier, }) async => false; @override Future installApp( IOSApp app, { - String userIdentifier, + String? userIdentifier, }) async => true; } @@ -151,12 +149,12 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override Future isAppInstalled( AndroidApk app, { - String userIdentifier, + String? userIdentifier, }) async => false; @override Future installApp( AndroidApk app, { - String userIdentifier, + String? userIdentifier, }) async => true; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart index c6550bdffad2b..2aaa015bbda78 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/logs.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart index 6db68d011d5fb..53ffc0d30c497 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -16,7 +14,7 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FakeCache cache; + late FakeCache cache; setUp(() { cache = FakeCache(); @@ -429,7 +427,7 @@ class FakeCache extends Fake implements Cache { bool isUpToDateValue = false; bool clearedStampFiles = false; bool locked = false; - Set artifacts; + Set? artifacts; @override Future lock() async { @@ -455,7 +453,7 @@ class FakeCache extends Fake implements Cache { } @override - Set platformOverrideArtifacts; + Set? platformOverrideArtifacts; @override bool includeAllPlatforms = false; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart index e70fcdc5afa03..1cfa8ff6c4dcd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:file/memory.dart'; @@ -24,18 +22,18 @@ import '../../src/context.dart'; import '../../src/fake_devices.dart'; void main() { - Daemon daemon; - NotifyingLogger notifyingLogger; - BufferLogger bufferLogger; - FakeAndroidDevice fakeDevice; + Daemon? daemon; + late NotifyingLogger notifyingLogger; + late BufferLogger bufferLogger; + late FakeAndroidDevice fakeDevice; - FakeApplicationPackageFactory applicationPackageFactory; - MemoryFileSystem memoryFileSystem; - FakeProcessManager fakeProcessManager; + late FakeApplicationPackageFactory applicationPackageFactory; + late MemoryFileSystem memoryFileSystem; + late FakeProcessManager fakeProcessManager; group('ProxiedDevices', () { - DaemonConnection serverDaemonConnection; - DaemonConnection clientDaemonConnection; + late DaemonConnection serverDaemonConnection; + late DaemonConnection clientDaemonConnection; setUp(() { bufferLogger = BufferLogger.test(); notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger); @@ -60,7 +58,7 @@ void main() { tearDown(() async { if (daemon != null) { - return daemon.shutdown(); + return daemon!.shutdown(); } notifyingLogger.dispose(); await serverDaemonConnection.dispose(); @@ -74,7 +72,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -95,7 +93,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -115,7 +113,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -145,7 +143,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -173,9 +171,9 @@ void main() { expect(launchResult.started, true); // The returned observatoryUri was a forwarded port, so we cannot compare them directly. - expect(launchResult.observatoryUri.path, observatoryUri.path); + expect(launchResult.observatoryUri!.path, observatoryUri.path); - expect(applicationPackageFactory.applicationBinaryRequested.readAsStringSync(), 'dummy content'); + expect(applicationPackageFactory.applicationBinaryRequested!.readAsStringSync(), 'dummy content'); expect(applicationPackageFactory.platformRequested, TargetPlatform.android_arm); expect(fakeDevice.startAppPackage, applicationPackage); @@ -197,7 +195,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -230,7 +228,7 @@ class FakeDaemonStreams implements DaemonStreams { } @override - void send(Map message, [ List binary ]) { + void send(Map message, [ List? binary ]) { outputs.add(DaemonMessage(message, binary != null ? Stream>.value(binary) : null)); } @@ -294,48 +292,48 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override bool get supportsStartPaused => true; - BuildMode supportsRuntimeModeCalledBuildMode; + BuildMode? supportsRuntimeModeCalledBuildMode; @override Future supportsRuntimeMode(BuildMode buildMode) async { supportsRuntimeModeCalledBuildMode = buildMode; return true; } - DeviceLogReader logReader; + late DeviceLogReader logReader; @override FutureOr getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) => logReader; - ApplicationPackage startAppPackage; - LaunchResult launchResult; + ApplicationPackage? startAppPackage; + late LaunchResult launchResult; @override Future startApp( ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs = const {}, + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { startAppPackage = package; return launchResult; } - ApplicationPackage stopAppPackage; + ApplicationPackage? stopAppPackage; @override Future stopApp( ApplicationPackage app, { - String userIdentifier, + String? userIdentifier, }) async { stopAppPackage = app; return true; } - List screenshot; + late List screenshot; @override Future takeScreenshot(File outputFile) { return outputFile.writeAsBytes(screenshot); @@ -347,10 +345,10 @@ class FakeDeviceLogReader implements DeviceLogReader { bool disposeCalled = false; @override - int appPid; + int? appPid; @override - FlutterVmService connectedVMService; + FlutterVmService? connectedVMService; @override void dispose() { @@ -366,12 +364,12 @@ class FakeDeviceLogReader implements DeviceLogReader { } class FakeApplicationPackageFactory implements ApplicationPackageFactory { - TargetPlatform platformRequested; - File applicationBinaryRequested; - ApplicationPackage applicationPackage; + TargetPlatform? platformRequested; + File? applicationBinaryRequested; + ApplicationPackage? applicationPackage; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { platformRequested = platform; applicationBinaryRequested = applicationBinary; return applicationPackage; @@ -382,5 +380,5 @@ class FakeApplicationPackage extends Fake implements ApplicationPackage {} class FakePrebuiltApplicationPackage extends Fake implements PrebuiltApplicationPackage { @override - File applicationPackage; + late File applicationPackage; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 4ebcb4ff40c51..8ad2c8787dcbb 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:file/file.dart'; @@ -31,7 +29,6 @@ import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart'; @@ -47,8 +44,8 @@ void main() { }); group('run', () { - FakeDeviceManager mockDeviceManager; - FileSystem fileSystem; + late FakeDeviceManager mockDeviceManager; + late FileSystem fileSystem; setUp(() { mockDeviceManager = FakeDeviceManager(); @@ -142,10 +139,10 @@ void main() { }); group('run app', () { - MemoryFileSystem fs; - Artifacts artifacts; - TestUsage usage; - FakeAnsiTerminal fakeTerminal; + late MemoryFileSystem fs; + late Artifacts artifacts; + late TestUsage usage; + late FakeAnsiTerminal fakeTerminal; setUpAll(() { Cache.disableLocking(); @@ -555,8 +552,8 @@ void main() { }); group('Fatal Logs', () { - TestRunCommandWithFakeResidentRunner command; - MemoryFileSystem fs; + late TestRunCommandWithFakeResidentRunner command; + late MemoryFileSystem fs; setUp(() { command = TestRunCommandWithFakeResidentRunner() @@ -666,7 +663,7 @@ void main() { }); group('dart-defines and web-renderer options', () { - List dartDefines; + late List dartDefines; setUp(() { dartDefines = []; @@ -707,7 +704,7 @@ void main() { }); group('terminal', () { - FakeAnsiTerminal fakeTerminal; + late FakeAnsiTerminal fakeTerminal; setUp(() { fakeTerminal = FakeAnsiTerminal(); @@ -877,7 +874,7 @@ void main() { expect(options.webLaunchUrl, 'http://flutter.dev'); final RegExp pattern = RegExp(r'^((http)?:\/\/)[^\s]+'); - expect(pattern.hasMatch(options.webLaunchUrl), true); + expect(pattern.hasMatch(options.webLaunchUrl!), true); }, overrides: { ProcessManager: () => FakeProcessManager.any(), Logger: () => BufferLogger.test(), @@ -889,7 +886,7 @@ class FakeDeviceManager extends Fake implements DeviceManager { List targetDevices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override bool hasSpecifiedAllDevices = false; @@ -903,7 +900,7 @@ class FakeDeviceManager extends Fake implements DeviceManager { } @override - Future> findTargetDevices(FlutterProject flutterProject, {Duration timeout}) async { + Future> findTargetDevices(FlutterProject? flutterProject, {Duration? timeout}) async { return targetDevices; } @@ -950,7 +947,7 @@ class FakeDevice extends Fake implements Device { @override String get id => 'fake_device'; - void _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code); + Never _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code); @override Future get isLocalEmulator => Future.value(_isLocalEmulator); @@ -987,7 +984,7 @@ class FakeDevice extends Fake implements Device { @override DeviceLogReader getLogReader({ - ApplicationPackage app, + ApplicationPackage? app, bool includePastLogs = false, }) { return FakeDeviceLogReader(); @@ -1002,27 +999,27 @@ class FakeDevice extends Fake implements Device { @override PlatformType get platformType => _platformType; - bool startAppSuccess; + late bool startAppSuccess; @override - DevFSWriter createDevFSWriter( - covariant ApplicationPackage app, - String userIdentifier, + DevFSWriter? createDevFSWriter( + covariant ApplicationPackage? app, + String? userIdentifier, ) { return null; } @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + required DebuggingOptions debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { if (startAppSuccess == false) { return LaunchResult.failed(); @@ -1045,19 +1042,18 @@ class FakeDevice extends Fake implements Device { } _throwToolExit(kSuccess); } - return null; } } class TestRunCommandWithFakeResidentRunner extends RunCommand { - FakeResidentRunner fakeResidentRunner; + late FakeResidentRunner fakeResidentRunner; @override Future createRunner({ - @required bool hotMode, - @required List flutterDevices, - @required String applicationBinaryPath, - @required FlutterProject flutterProject, + required bool hotMode, + required List flutterDevices, + required String? applicationBinaryPath, + required FlutterProject flutterProject, }) async { return fakeResidentRunner; } @@ -1077,26 +1073,26 @@ class TestRunCommandThatOnlyValidates extends RunCommand { } class FakeResidentRunner extends Fake implements ResidentRunner { - RPCError rpcError; + RPCError? rpcError; @override Future run({ - Completer connectionInfoCompleter, - Completer appStartedCompleter, + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, bool enableDevTools = false, - String route, + String? route, }) async { await null; if (rpcError != null) { - throw rpcError; + throw rpcError!; } return 0; } } class DaemonCapturingRunCommand extends RunCommand { - /*late*/ Daemon daemon; - /*late*/ CapturingAppDomain appDomain; + late Daemon daemon; + late CapturingAppDomain appDomain; @override Daemon createMachineDaemon() { @@ -1108,29 +1104,29 @@ class DaemonCapturingRunCommand extends RunCommand { } class CapturingAppDomain extends AppDomain { - CapturingAppDomain(Daemon daemon) : super(daemon); + CapturingAppDomain(super.daemon); - bool /*?*/ multidexEnabled; - String /*?*/ userIdentifier; + bool? multidexEnabled; + String? userIdentifier; @override Future startApp( Device device, String projectDirectory, String target, - String route, + String? route, DebuggingOptions options, bool enableHotReload, { - File applicationBinary, - @required bool trackWidgetCreation, - String projectRootPath, - String packagesFilePath, - String dillOutputPath, + File? applicationBinary, + required bool trackWidgetCreation, + String? projectRootPath, + String? packagesFilePath, + String? dillOutputPath, bool ipv6 = false, bool multidexEnabled = false, - String isolateFilter, + String? isolateFilter, bool machine = true, - String userIdentifier, + String? userIdentifier, }) async { this.multidexEnabled = multidexEnabled; this.userIdentifier = userIdentifier; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart index 2e075d4c972b3..8c005b69decc3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -23,7 +21,7 @@ void main() { testUsingContext('rasterizer and skia screenshots do not require a device', () async { // Throw a specific exception when attempting to make a VM Service connection to // verify that we've made it past the initial validation. - openChannelForTesting = (String url, {CompressionOptions compression, Logger logger}) async { + openChannelForTesting = (String url, {CompressionOptions? compression, Logger? logger}) async { expect(url, 'ws://localhost:8181/ws'); throw Exception('dummy'); }; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart index 97bfd1c32ac56..5e632024bfc31 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -18,7 +16,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('shell_completion', () { - FakeStdio fakeStdio; + late FakeStdio fakeStdio; setUp(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart index c58c14aab74f8..fb5d1810db604 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:typed_data'; @@ -15,7 +13,6 @@ import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/symbolize.dart'; import 'package:flutter_tools/src/convert.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -24,8 +21,8 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - MemoryFileSystem fileSystem; - FakeStdio stdio; + late MemoryFileSystem fileSystem; + late FakeStdio stdio; setUpAll(() { Cache.disableLocking(); @@ -69,7 +66,7 @@ void main() { OutputPreferences: () => OutputPreferences.test(), }); - testUsingContext('symbolize exits when --debug-info file is missing', () async { + testUsingContext('symbolize exits when --debug-info dwarf file is missing', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, @@ -83,6 +80,20 @@ void main() { OutputPreferences: () => OutputPreferences.test(), }); + testUsingContext('symbolize exits when --debug-info dSYM is missing', () async { + final SymbolizeCommand command = SymbolizeCommand( + stdio: stdio, + fileSystem: fileSystem, + dwarfSymbolizationService: DwarfSymbolizationService.test(), + ); + final Future result = createTestCommandRunner(command) + .run(const ['symbolize', '--debug-info=app.dSYM']); + + expect(result, throwsToolExit(message: 'app.dSYM does not exist.')); + }, overrides: { + OutputPreferences: () => OutputPreferences.test(), + }); + testUsingContext('symbolize exits when --input file is missing', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, @@ -140,9 +151,9 @@ void main() { class ThrowingDwarfSymbolizationService extends Fake implements DwarfSymbolizationService { @override Future decode({ - @required Stream> input, - @required IOSink output, - @required Uint8List symbols, + required Stream> input, + required IOSink output, + required Uint8List symbols, }) async { throwToolExit('test'); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index ecf81933ee9cd..8fa700837adb3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:convert'; @@ -12,7 +10,8 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/test.dart'; import 'package:flutter_tools/src/device.dart'; @@ -22,7 +21,6 @@ import 'package:flutter_tools/src/test/runner.dart'; import 'package:flutter_tools/src/test/test_time_recorder.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; import 'package:flutter_tools/src/test/watcher.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -59,8 +57,8 @@ final String _packageConfigContents = json.encode({ void main() { Cache.disableLocking(); - MemoryFileSystem fs; - LoggingLogger logger; + late MemoryFileSystem fs; + late LoggingLogger logger; setUp(() { fs = MemoryFileSystem.test(); @@ -790,51 +788,47 @@ class FakeFlutterTestRunner implements FlutterTestRunner { FakeFlutterTestRunner(this.exitCode, [this.leastRunTime]); int exitCode; - Duration leastRunTime; - bool lastEnableObservatoryValue; - DebuggingOptions lastDebuggingOptionsValue; + Duration? leastRunTime; + bool? lastEnableObservatoryValue; + late DebuggingOptions lastDebuggingOptionsValue; @override Future runTests( TestWrapper testWrapper, List testFiles, { - @required DebuggingOptions debuggingOptions, - Directory workDir, + required DebuggingOptions debuggingOptions, List names = const [], List plainNames = const [], - String tags, - String excludeTags, + String? tags, + String? excludeTags, bool enableObservatory = false, bool ipv6 = false, bool machine = false, - String precompiledDillPath, - Map precompiledDillFiles, - BuildMode buildMode, - bool trackWidgetCreation = false, + String? precompiledDillPath, + Map? precompiledDillFiles, bool updateGoldens = false, - TestWatcher watcher, - int concurrency, - String testAssetDirectory, - FlutterProject flutterProject, - String icudtlPath, - Directory coverageDirectory, + TestWatcher? watcher, + required int? concurrency, + String? testAssetDirectory, + FlutterProject? flutterProject, + String? icudtlPath, + Directory? coverageDirectory, bool web = false, - String randomSeed, - @override List extraFrontEndOptions, - String reporter, - String timeout, + String? randomSeed, + String? reporter, + String? timeout, bool runSkipped = false, - int shardIndex, - int totalShards, - Device integrationTestDevice, - String integrationTestUserIdentifier, - TestTimeRecorder testTimeRecorder, + int? shardIndex, + int? totalShards, + Device? integrationTestDevice, + String? integrationTestUserIdentifier, + TestTimeRecorder? testTimeRecorder, }) async { lastEnableObservatoryValue = enableObservatory; lastDebuggingOptionsValue = debuggingOptions; if (leastRunTime != null) { - await Future.delayed(leastRunTime); + await Future.delayed(leastRunTime!); } return exitCode; @@ -842,7 +836,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner { } class FakePackageTest implements TestWrapper { - List lastArgs; + List? lastArgs; @override Future main(List args) async { @@ -857,7 +851,7 @@ class FakePackageTest implements TestWrapper { } class _FakeDeviceManager extends DeviceManager { - _FakeDeviceManager(this._connectedDevices); + _FakeDeviceManager(this._connectedDevices) : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); final List _connectedDevices; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart index 5e31c7ec3dd71..1bfdb01ea8ba4 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:args/command_runner.dart'; @@ -20,12 +18,12 @@ import '../../src/fakes.dart' show FakeFlutterVersion; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - FakeProcessManager processManager; + late FileSystem fileSystem; + late BufferLogger logger; + late FakeProcessManager processManager; UpgradeCommand command; - CommandRunner runner; - FlutterVersion flutterVersion; + late CommandRunner runner; + late FlutterVersion flutterVersion; setUpAll(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart index 27c26878e489d..b3d346dc1cbac 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -16,7 +14,6 @@ import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../../src/android_common.dart'; @@ -29,7 +26,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); - Future runCommandIn(String target, { List arguments }) async { + Future runCommandIn(String target, { List? arguments }) async { final BuildAarCommand command = BuildAarCommand(verboseHelp: false); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -42,8 +39,8 @@ void main() { } group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -110,8 +107,8 @@ void main() { }); group('flag parsing', () { - Directory tempDir; - FakeAndroidBuilder fakeAndroidBuilder; + late Directory tempDir; + late FakeAndroidBuilder fakeAndroidBuilder; setUp(() { fakeAndroidBuilder = FakeAndroidBuilder(); @@ -193,11 +190,11 @@ void main() { }); group('Gradle', () { - Directory tempDir; - AndroidSdk mockAndroidSdk; - String gradlew; - FakeProcessManager processManager; - String flutterRoot; + late Directory tempDir; + late AndroidSdk mockAndroidSdk; + late String gradlew; + late FakeProcessManager processManager; + late String flutterRoot; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -277,7 +274,7 @@ void main() { Future runBuildAarCommand( String target, { - List arguments, + List? arguments, }) async { final BuildAarCommand command = BuildAarCommand(verboseHelp: false); final CommandRunner runner = createTestCommandRunner(command); @@ -291,19 +288,19 @@ Future runBuildAarCommand( } class FakeAndroidBuilder extends Fake implements AndroidBuilder { - FlutterProject project; - Set androidBuildInfo; - String target; - String outputDirectoryPath; - String buildNumber; + late FlutterProject project; + late Set androidBuildInfo; + late String target; + String? outputDirectoryPath; + late String buildNumber; @override Future buildAar({ - @required FlutterProject project, - @required Set androidBuildInfo, - @required String target, - @required String outputDirectoryPath, - @required String buildNumber, + required FlutterProject project, + required Set androidBuildInfo, + required String target, + String? outputDirectoryPath, + required String buildNumber, }) async { this.project = project; this.androidBuildInfo = androidBuildInfo; diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart index 52178121c2a0f..19540e56de6ce 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -26,8 +24,8 @@ void main() { Cache.disableLocking(); group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -108,11 +106,11 @@ void main() { }); group('Gradle', () { - Directory tempDir; - FakeProcessManager processManager; - String gradlew; - AndroidSdk mockAndroidSdk; - TestUsage testUsage; + late Directory tempDir; + late FakeProcessManager processManager; + late String gradlew; + late AndroidSdk mockAndroidSdk; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -429,7 +427,7 @@ void main() { Future runBuildApkCommand( String target, { - List arguments, + List? arguments, }) async { final BuildApkCommand command = BuildApkCommand(); final CommandRunner runner = createTestCommandRunner(command); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart index 5b5b94ac55fc3..9f2126716893c 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -24,8 +22,8 @@ void main() { Cache.disableLocking(); group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -87,10 +85,10 @@ void main() { }); group('Gradle', () { - Directory tempDir; - FakeProcessManager processManager; - FakeAndroidSdk fakeAndroidSdk; - TestUsage testUsage; + late Directory tempDir; + late FakeProcessManager processManager; + late FakeAndroidSdk fakeAndroidSdk; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -213,7 +211,7 @@ void main() { Future runBuildAppBundleCommand( String target, { - List arguments, + List? arguments, }) async { final BuildAppBundleCommand command = BuildAppBundleCommand(); final CommandRunner runner = createTestCommandRunner(command); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart index be306270c9a4b..772afccc56916 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -27,8 +25,8 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); - Directory tempDir; - FakeBundleBuilder fakeBundleBuilder; + late Directory tempDir; + late FakeBundleBuilder fakeBundleBuilder; final FileSystemStyle fileSystemStyle = globals.fs.path.separator == '/' ? FileSystemStyle.posix : FileSystemStyle.windows; @@ -46,7 +44,7 @@ void main() { return MemoryFileSystem.test(style: fileSystemStyle); } - Future runCommandIn(String projectPath, { List arguments }) async { + Future runCommandIn(String projectPath, { List? arguments }) async { final BuildBundleCommand command = BuildBundleCommand(bundleBuilder: fakeBundleBuilder); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -470,14 +468,14 @@ void main() { class FakeBundleBuilder extends Fake implements BundleBuilder { @override Future build({ - @required TargetPlatform platform, - @required BuildInfo buildInfo, - FlutterProject project, - String mainPath, + required TargetPlatform platform, + required BuildInfo buildInfo, + FlutterProject? project, + String? mainPath, String manifestPath = defaultManifestPath, - String applicationKernelFilePath, - String depfilePath, - String assetDirPath, - @visibleForTesting BuildSystem buildSystem, + String? applicationKernelFilePath, + String? depfilePath, + String? assetDirPath, + @visibleForTesting BuildSystem? buildSystem, }) async {} } diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 6352dd37f2806..47ef02afd8d11 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:convert'; import 'dart:io' as io; @@ -60,12 +58,12 @@ const String samplesIndexJson = ''' ]'''; void main() { - Directory tempDir; - Directory projectDir; - FakeFlutterVersion fakeFlutterVersion; - LoggingProcessManager loggingProcessManager; - FakeProcessManager fakeProcessManager; - BufferLogger logger; + late Directory tempDir; + late Directory projectDir; + late FakeFlutterVersion fakeFlutterVersion; + late LoggingProcessManager loggingProcessManager; + late FakeProcessManager fakeProcessManager; + late BufferLogger logger; setUpAll(() async { Cache.disableLocking(); @@ -569,7 +567,7 @@ void main() { // Expect the dependency on flutter_web_plugins exists expect(pubspec.dependencies, contains('flutter_web_plugins')); // The platform is correctly registered - final YamlMap web = ((pubspec.flutter['plugin'] as YamlMap)['platforms'] as YamlMap)['web'] as YamlMap; + final YamlMap web = ((pubspec.flutter!['plugin'] as YamlMap)['platforms'] as YamlMap)['web'] as YamlMap; expect(web['pluginClass'], 'FlutterProjectWeb'); expect(web['fileName'], 'flutter_project_web.dart'); expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); @@ -599,7 +597,7 @@ void main() { final String pluginName = projectDir.basename; expect(pubspec.dependencies, contains(pluginName)); expect(pubspec.dependencies[pluginName] is PathDependency, isTrue); - final PathDependency pathDependency = pubspec.dependencies[pluginName] as PathDependency; + final PathDependency pathDependency = pubspec.dependencies[pluginName]! as PathDependency; expect(pathDependency.path, '../'); }, overrides: { Pub: () => Pub( @@ -1158,7 +1156,7 @@ void main() { final String original = file.readAsStringSync(); final Process process = await Process.start( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, ['format', '--output=show', file.path], workingDirectory: projectDir.path, ); @@ -1255,7 +1253,7 @@ void main() { final String original = file.readAsStringSync(); final Process process = await Process.start( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, ['format', '--output=show', file.path], workingDirectory: projectDir.path, ); @@ -2548,9 +2546,9 @@ void main() { await runner.run(['create', '--no-pub', '--template=plugin', projectDir.path]); final String rawPubspec = await projectDir.childFile('pubspec.yaml').readAsString(); final Pubspec pubspec = Pubspec.parse(rawPubspec); - final Map env = pubspec.environment; - expect(env['flutter'].allows(Version(2, 5, 0)), true); - expect(env['flutter'].allows(Version(2, 4, 9)), false); + final Map env = pubspec.environment!; + expect(env['flutter']!.allows(Version(2, 5, 0)), true); + expect(env['flutter']!.allows(Version(2, 4, 9)), false); }); testUsingContext('default app uses flutter default versions', () async { @@ -3084,7 +3082,7 @@ Future _analyzeProject(String workingDir, { List expectedFailures ]; final ProcessResult exec = await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, args, workingDirectory: workingDir, ); @@ -3124,7 +3122,7 @@ Future _getPackages(Directory workingDir) async { // While flutter test does get packages, it doesn't write version // files anymore. await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, [ flutterToolsSnapshotPath, 'packages', @@ -3134,7 +3132,7 @@ Future _getPackages(Directory workingDir) async { ); } -Future _runFlutterTest(Directory workingDir, { String target }) async { +Future _runFlutterTest(Directory workingDir, { String? target }) async { final String flutterToolsSnapshotPath = globals.fs.path.absolute(globals.fs.path.join( '..', '..', @@ -3153,7 +3151,7 @@ Future _runFlutterTest(Directory workingDir, { String target }) async { ]; final ProcessResult exec = await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, args, workingDirectory: workingDir.path, ); @@ -3171,8 +3169,8 @@ class LoggingProcessManager extends LocalProcessManager { @override Future start( List command, { - String workingDirectory, - Map environment, + String? workingDirectory, + Map? environment, bool includeParentEnvironment = true, bool runInShell = false, ProcessStartMode mode = ProcessStartMode.normal, @@ -3193,14 +3191,14 @@ class LoggingProcessManager extends LocalProcessManager { } } -String _getStringValueFromPlist({File plistFile, String key}) { +String _getStringValueFromPlist({required File plistFile, String? key}) { final List plist = plistFile.readAsLinesSync().map((String line) => line.trim()).toList(); final int keyIndex = plist.indexOf('$key'); assert(keyIndex > 0); return plist[keyIndex+1].replaceAll('', '').replaceAll('', ''); } -bool _getBooleanValueFromPlist({File plistFile, String key}) { +bool _getBooleanValueFromPlist({required File plistFile, String? key}) { final List plist = plistFile.readAsLinesSync().map((String line) => line.trim()).toList(); final int keyIndex = plist.indexOf('$key'); assert(keyIndex > 0); diff --git a/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart b/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart index a73f7a1b198fe..c1e16e1c30d4f 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:convert'; import 'package:args/command_runner.dart'; @@ -20,8 +18,8 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FakeDeviceManager deviceManager; - BufferLogger logger; + late FakeDeviceManager deviceManager; + late BufferLogger logger; setUpAll(() { Cache.disableLocking(); @@ -87,10 +85,10 @@ class FakeDeviceManager extends Fake implements DeviceManager { List devices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override - Future> refreshAllConnectedDevices({Duration timeout}) async { + Future> refreshAllConnectedDevices({Duration? timeout}) async { return devices; } } diff --git a/packages/flutter_tools/test/commands.shard/permeable/format_test.dart b/packages/flutter_tools/test/commands.shard/permeable/format_test.dart index 942dbd266ac4a..7a154bd0604c2 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/format_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/format_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -16,7 +14,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('format', () { - Directory tempDir; + late Directory tempDir; setUp(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart index 8b2e5532a1acb..b522f1d6b37ee 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart index 4e1ee2dc15870..26b6b9233a7dd 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart index 1ff6acae1daa2..3df997c78a2cf 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart index 8ca503852b29e..a145dd702724d 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - // TODO(gspencergoog): Remove this tag once this test's state leaks/test // dependencies have been fixed. // https://github.com/flutter/flutter/issues/85160 @@ -34,7 +32,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); group('packages get/upgrade', () { - Directory tempDir; + late Directory tempDir; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -44,7 +42,7 @@ void main() { tryToDelete(tempDir); }); - Future createProjectWithPlugin(String plugin, { List arguments }) async { + Future createProjectWithPlugin(String plugin, { List? arguments }) async { final String projectPath = await createProject(tempDir, arguments: arguments); final File pubspec = globals.fs.file(globals.fs.path.join(projectPath, 'pubspec.yaml')); String content = await pubspec.readAsString(); @@ -60,7 +58,7 @@ void main() { return projectPath; } - Future runCommandIn(String projectPath, String verb, { List args }) async { + Future runCommandIn(String projectPath, String verb, { List? args }) async { final PackagesCommand command = PackagesCommand(); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -243,7 +241,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesNumberPlugins, 0); }, overrides: { @@ -265,7 +263,7 @@ void main() { final String exampleProjectPath = globals.fs.path.join(projectPath, 'example'); final PackagesCommand command = await runCommandIn(exampleProjectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesNumberPlugins, 1); }, overrides: { @@ -285,7 +283,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesProjectModule, false); }, overrides: { @@ -305,7 +303,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesProjectModule, true); }, overrides: { @@ -334,7 +332,7 @@ void main() { androidManifest.writeAsStringSync(updatedAndroidManifestString); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v1'); }, overrides: { @@ -354,7 +352,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v2'); }, overrides: { @@ -439,8 +437,8 @@ void main() { }); group('packages test/pub', () { - FakeProcessManager processManager; - FakeStdio mockStdio; + late FakeProcessManager processManager; + late FakeStdio mockStdio; setUp(() { processManager = FakeProcessManager.empty(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/script_test.dart b/packages/flutter_tools/test/commands.shard/permeable/script_test.dart index 65869d9b2858b..a28cd5cfa2f13 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/script_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/script_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:io'; import 'package:flutter_tools/src/cache.dart'; diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart index b905b8aaa240b..ae507da6b5235 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -23,10 +21,10 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('UpgradeCommandRunner', () { - FakeUpgradeCommandRunner fakeCommandRunner; - UpgradeCommandRunner realCommandRunner; - FakeProcessManager processManager; - FakePlatform fakePlatform; + late FakeUpgradeCommandRunner fakeCommandRunner; + late UpgradeCommandRunner realCommandRunner; + late FakeProcessManager processManager; + late FakePlatform fakePlatform; const GitTagVersion gitTagVersion = GitTagVersion( x: 1, y: 2, @@ -349,7 +347,7 @@ void main() { }); testUsingContext('does not throw on unknown tag, official branch, force', () async { - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); final Future result = fakeCommandRunner.runCommand( @@ -369,7 +367,7 @@ void main() { testUsingContext('does not throw tool exit with uncommitted changes and force', () async { final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); fakeCommandRunner.willHaveUncommittedChanges = true; final Future result = fakeCommandRunner.runCommand( @@ -389,7 +387,7 @@ void main() { testUsingContext("Doesn't throw on known tag, beta branch, no force", () async { final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); final Future result = fakeCommandRunner.runCommand( force: false, @@ -407,9 +405,9 @@ void main() { }); group('full command', () { - FakeProcessManager fakeProcessManager; - Directory tempDir; - File flutterToolState; + late FakeProcessManager fakeProcessManager; + late Directory tempDir; + late File flutterToolState; setUp(() { Cache.disableLocking(); @@ -470,10 +468,10 @@ class FakeUpgradeCommandRunner extends UpgradeCommandRunner { bool willHaveUncommittedChanges = false; bool alreadyUpToDate = false; - FlutterVersion remoteVersion; + late FlutterVersion remoteVersion; @override - Future fetchLatestVersion({FlutterVersion localVersion}) async => remoteVersion; + Future fetchLatestVersion({FlutterVersion? localVersion}) async => remoteVersion; @override Future hasUncommittedChanges() async => willHaveUncommittedChanges; diff --git a/packages/flutter_tools/test/data/fuchsia_test/main/.packages b/packages/flutter_tools/test/data/fuchsia_test/main/.packages deleted file mode 100644 index 9882eb023ec6c..0000000000000 --- a/packages/flutter_tools/test/data/fuchsia_test/main/.packages +++ /dev/null @@ -1 +0,0 @@ -testo:lib/ \ No newline at end of file diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index 0a37c63fa2208..99fca3a81b25e 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/android/gradle_errors.dart'; @@ -13,8 +11,8 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/terminal.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -22,6 +20,14 @@ import '../../src/fake_process_manager.dart'; import '../../src/fakes.dart'; void main() { + late FileSystem fileSystem; + late FakeProcessManager processManager; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + processManager = FakeProcessManager.empty(); + }); + group('gradleErrors', () { testWithoutContext('list of errors', () { // If you added a new Gradle error, please update this test. @@ -64,7 +70,12 @@ at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128) at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -72,8 +83,8 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if gradle fails downloading with proxy error', () async { @@ -94,7 +105,12 @@ at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128) at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -102,8 +118,8 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if gradle times out waiting for exclusive access to zip', () async { @@ -115,7 +131,12 @@ Exception in thread "main" java.lang.RuntimeException: Timeout of 120000 reached at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -123,8 +144,8 @@ Exception in thread "main" java.lang.RuntimeException: Timeout of 120000 reached ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if remote host closes connection', () async { @@ -152,7 +173,12 @@ Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host clos at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -160,8 +186,8 @@ Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host clos ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if file opening fails', () async { @@ -181,7 +207,12 @@ Exception in thread "main" java.io.FileNotFoundException: https://downloads.grad at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -189,8 +220,8 @@ Exception in thread "main" java.io.FileNotFoundException: https://downloads.grad ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if the connection is reset', () async { @@ -221,7 +252,12 @@ Exception in thread "main" java.net.SocketException: Connection reset at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -229,8 +265,8 @@ Exception in thread "main" java.net.SocketException: Connection reset ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if Gradle could not get a resource', () async { @@ -248,7 +284,12 @@ A problem occurred configuring root project 'android'. > Could not GET 'https://jcenter.bintray.com/net/sf/proguard/proguard-parent/6.0.3/proguard-parent-6.0.3.pom'. Received status code 504 from server: Gateway Time-out'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -256,8 +297,8 @@ A problem occurred configuring root project 'android'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if Gradle could not get a resource (non-Gateway)', () async { @@ -279,7 +320,12 @@ A problem occurred configuring root project 'android'. > Remote host closed connection during handshake'''; expect(formatTestErrorMessage(errorMessage, networkErrorHandler), isTrue); - expect(await networkErrorHandler.handler(), equals(GradleBuildStatus.retry)); + expect(await networkErrorHandler.handler( + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + usesAndroidX: true, + ), equals(GradleBuildStatus.retry)); expect(testLogger.errorText, contains( @@ -287,8 +333,8 @@ A problem occurred configuring root project 'android'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -318,7 +364,7 @@ Execution failed for task ':app:mergeDexDebug'. Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html'''; expect(formatTestErrorMessage(errorMessage, multidexErrorHandler), isTrue); - expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(globals.fs.currentDirectory), multidexEnabled: true), equals(GradleBuildStatus.exit)); + expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(fileSystem.currentDirectory), multidexEnabled: true, usesAndroidX: true, line: ''), equals(GradleBuildStatus.exit)); expect(testLogger.statusText, contains( @@ -336,8 +382,8 @@ Execution failed for task ':app:mergeDexDebug'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('retries if multidex support enabled', () async { const String errorMessage = r''' @@ -363,7 +409,7 @@ Execution failed for task ':app:mergeDexDebug'. The number of method references in a .dex file cannot exceed 64K. Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html'''; - final File manifest = globals.fs.currentDirectory + final File manifest = fileSystem.currentDirectory .childDirectory('android') .childDirectory('app') .childDirectory('src') @@ -382,7 +428,7 @@ Execution failed for task ':app:mergeDexDebug'. ''', flush: true); expect(formatTestErrorMessage(errorMessage, multidexErrorHandler), isTrue); - expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(globals.fs.currentDirectory), multidexEnabled: true), equals(GradleBuildStatus.retry)); + expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(fileSystem.currentDirectory), multidexEnabled: true, line: '', usesAndroidX: true), equals(GradleBuildStatus.retry)); expect(testLogger.statusText, contains( @@ -395,8 +441,8 @@ Execution failed for task ':app:mergeDexDebug'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, AnsiTerminal: () => _TestPromptTerminal('y'), }); @@ -424,7 +470,7 @@ Execution failed for task ':app:mergeDexDebug'. The number of method references in a .dex file cannot exceed 64K. Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html'''; - final File manifest = globals.fs.currentDirectory + final File manifest = fileSystem.currentDirectory .childDirectory('android') .childDirectory('app') .childDirectory('src') @@ -443,7 +489,7 @@ Execution failed for task ':app:mergeDexDebug'. ''', flush: true); expect(formatTestErrorMessage(errorMessage, multidexErrorHandler), isTrue); - expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(globals.fs.currentDirectory), multidexEnabled: true), equals(GradleBuildStatus.exit)); + expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(fileSystem.currentDirectory), multidexEnabled: true, line: '', usesAndroidX: true), equals(GradleBuildStatus.exit)); expect(testLogger.statusText, contains( @@ -461,8 +507,8 @@ Execution failed for task ':app:mergeDexDebug'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, AnsiTerminal: () => _TestPromptTerminal('n'), }); @@ -491,7 +537,7 @@ Execution failed for task ':app:mergeDexDebug'. Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html'''; expect(formatTestErrorMessage(errorMessage, multidexErrorHandler), isTrue); - expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(globals.fs.currentDirectory), multidexEnabled: false), equals(GradleBuildStatus.exit)); + expect(await multidexErrorHandler.handler(project: FlutterProject.fromDirectory(fileSystem.currentDirectory), multidexEnabled: false, line: '', usesAndroidX: true), equals(GradleBuildStatus.exit)); expect(testLogger.statusText, contains( @@ -499,8 +545,8 @@ Execution failed for task ':app:mergeDexDebug'. ) ); }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -511,7 +557,12 @@ Permission denied Command: /home/android/gradlew assembleRelease '''; expect(formatTestErrorMessage(errorMessage, permissionDeniedErrorHandler), isTrue); - expect(await permissionDeniedErrorHandler.handler(), equals(GradleBuildStatus.exit)); + expect(await permissionDeniedErrorHandler.handler( + usesAndroidX: true, + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + ), equals(GradleBuildStatus.exit)); expect( testLogger.statusText, @@ -541,7 +592,12 @@ Command: /home/android/gradlew assembleRelease }); testUsingContext('handler', () async { - expect(await permissionDeniedErrorHandler.handler(), equals(GradleBuildStatus.exit)); + expect(await permissionDeniedErrorHandler.handler( + usesAndroidX: true, + line: '', + multidexEnabled: true, + project: FakeFlutterProject(), + ), equals(GradleBuildStatus.exit)); expect( testLogger.statusText, @@ -574,7 +630,9 @@ Command: /home/android/gradlew assembleRelease testUsingContext('handler', () async { await licenseNotAcceptedHandler.handler( line: 'You have not accepted the license agreements of the following SDK components: [foo, bar]', - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + multidexEnabled: true, ); expect( @@ -594,12 +652,6 @@ Command: /home/android/gradlew assembleRelease }); group('flavor undefined', () { - FakeProcessManager fakeProcessManager; - - setUp(() { - fakeProcessManager = FakeProcessManager.empty(); - }); - testWithoutContext('pattern', () { expect( flavorUndefinedHandler.test( @@ -628,7 +680,7 @@ Command: /home/android/gradlew assembleRelease }); testUsingContext('handler - with flavor', () async { - fakeProcessManager.addCommand(const FakeCommand( + processManager.addCommand(const FakeCommand( command: [ 'gradlew', 'app:tasks' , @@ -649,7 +701,10 @@ assembleFooTest )); await flavorUndefinedHandler.handler( - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + line: '', + multidexEnabled: true, ); expect( @@ -671,16 +726,16 @@ assembleFooTest '└─────────────────────────────────────────────────────────────────────────────────────────────────┘\n' ) ); - expect(fakeProcessManager, hasNoRemainingExpectations); + expect(processManager, hasNoRemainingExpectations); }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - ProcessManager: () => fakeProcessManager, - FileSystem: () => MemoryFileSystem.test(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext('handler - without flavor', () async { - fakeProcessManager.addCommand(const FakeCommand( + processManager.addCommand(const FakeCommand( command: [ 'gradlew', 'app:tasks' , @@ -695,7 +750,10 @@ assembleProfile )); await flavorUndefinedHandler.handler( - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + line: '', + multidexEnabled: true, ); expect( @@ -710,12 +768,12 @@ assembleProfile '└───────────────────────────────────────────────────────────────────────────────────────────────┘\n' ) ); - expect(fakeProcessManager, hasNoRemainingExpectations); + expect(processManager, hasNoRemainingExpectations); }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - ProcessManager: () => fakeProcessManager, - FileSystem: () => MemoryFileSystem.test(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -732,7 +790,9 @@ assembleProfile testUsingContext('suggestion', () async { await minSdkVersionHandler.handler( line: stdoutLine, - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + multidexEnabled: true, ); expect( @@ -759,8 +819,8 @@ assembleProfile }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -777,7 +837,10 @@ assembleProfile testUsingContext('suggestion', () async { await transformInputIssueHandler.handler( - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + line: '', + multidexEnabled: true, ); expect( @@ -798,8 +861,8 @@ assembleProfile }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -819,7 +882,10 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. testUsingContext('suggestion', () async { await lockFileDepMissingHandler.handler( - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + line: '', + multidexEnabled: true, ); expect( @@ -836,8 +902,8 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -855,7 +921,10 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. testUsingContext('suggestion', () async { await incompatibleKotlinVersionHandler.handler( - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + line: '', + multidexEnabled: true, ); expect( @@ -873,8 +942,8 @@ Execution failed for task ':app:generateDebugFeatureTransitiveDeps'. }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -895,7 +964,9 @@ A problem occurred evaluating project ':app'. testUsingContext('suggestion', () async { await outdatedGradleHandler.handler( line: errorMessage, - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + multidexEnabled: true, ); expect( @@ -918,8 +989,8 @@ A problem occurred evaluating project ':app'. }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -952,7 +1023,9 @@ Execution failed for task ':app:checkDebugAarMetadata'. testUsingContext('suggestion', () async { await minCompileSdkVersionHandler.handler( line: errorMessage, - project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), + project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + usesAndroidX: true, + multidexEnabled: true, ); expect( @@ -971,8 +1044,8 @@ Execution failed for task ':app:checkDebugAarMetadata'. }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -994,7 +1067,12 @@ A problem occurred evaluating project ':flutter'. }); testUsingContext('suggestion', () async { - await jvm11RequiredHandler.handler(); + await jvm11RequiredHandler.handler( + project: FakeFlutterProject(), + usesAndroidX: true, + line: '', + multidexEnabled: true, + ); expect( testLogger.statusText, @@ -1013,8 +1091,8 @@ A problem occurred evaluating project ':flutter'. }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -1069,7 +1147,12 @@ at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:108)''' }); testUsingContext('suggestion', () async { - final GradleBuildStatus status = await sslExceptionHandler.handler(); + final GradleBuildStatus status = await sslExceptionHandler.handler( + project: FakeFlutterProject(), + usesAndroidX: true, + line: '', + multidexEnabled: true, + ); expect(status, GradleBuildStatus.retry); expect(testLogger.errorText, @@ -1080,8 +1163,8 @@ at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:108)''' }, overrides: { GradleUtils: () => FakeGradleUtils(), Platform: () => fakePlatform('android'), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); }); @@ -1108,12 +1191,17 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''' }); testUsingContext('suggestion', () async { - globals.fs.file('foo/.gradle/fizz.zip').createSync(recursive: true); + fileSystem.file('foo/.gradle/fizz.zip').createSync(recursive: true); - final GradleBuildStatus result = await zipExceptionHandler.handler(); + final GradleBuildStatus result = await zipExceptionHandler.handler( + project: FakeFlutterProject(), + usesAndroidX: true, + line: '', + multidexEnabled: true, + ); expect(result, equals(GradleBuildStatus.retry)); - expect(globals.fs.file('foo/.gradle/fizz.zip'), exists); + expect(fileSystem.file('foo/.gradle/fizz.zip'), exists); expect( testLogger.errorText, contains( @@ -1123,18 +1211,23 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''' expect(testLogger.statusText, ''); }, overrides: { Platform: () => FakePlatform(environment: {'HOME': 'foo/'}), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, BotDetector: () => const FakeBotDetector(false), }); testUsingContext('suggestion if running as bot', () async { - globals.fs.file('foo/.gradle/fizz.zip').createSync(recursive: true); + fileSystem.file('foo/.gradle/fizz.zip').createSync(recursive: true); - final GradleBuildStatus result = await zipExceptionHandler.handler(); + final GradleBuildStatus result = await zipExceptionHandler.handler( + project: FakeFlutterProject(), + usesAndroidX: true, + line: '', + multidexEnabled: true, + ); expect(result, equals(GradleBuildStatus.retry)); - expect(globals.fs.file('foo/.gradle/fizz.zip'), isNot(exists)); + expect(fileSystem.file('foo/.gradle/fizz.zip'), isNot(exists)); expect( testLogger.errorText, @@ -1148,18 +1241,23 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''' ); }, overrides: { Platform: () => FakePlatform(environment: {'HOME': 'foo/'}), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, BotDetector: () => const FakeBotDetector(true), }); testUsingContext('suggestion if stdin has terminal and user entered y', () async { - globals.fs.file('foo/.gradle/fizz.zip').createSync(recursive: true); + fileSystem.file('foo/.gradle/fizz.zip').createSync(recursive: true); - final GradleBuildStatus result = await zipExceptionHandler.handler(); + final GradleBuildStatus result = await zipExceptionHandler.handler( + line: '', + usesAndroidX: true, + multidexEnabled: true, + project: FakeFlutterProject(), + ); expect(result, equals(GradleBuildStatus.retry)); - expect(globals.fs.file('foo/.gradle/fizz.zip'), isNot(exists)); + expect(fileSystem.file('foo/.gradle/fizz.zip'), isNot(exists)); expect( testLogger.errorText, contains( @@ -1172,19 +1270,24 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''' ); }, overrides: { Platform: () => FakePlatform(environment: {'HOME': 'foo/'}), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, AnsiTerminal: () => _TestPromptTerminal('y'), BotDetector: () => const FakeBotDetector(false), }); testUsingContext('suggestion if stdin has terminal and user entered n', () async { - globals.fs.file('foo/.gradle/fizz.zip').createSync(recursive: true); + fileSystem.file('foo/.gradle/fizz.zip').createSync(recursive: true); - final GradleBuildStatus result = await zipExceptionHandler.handler(); + final GradleBuildStatus result = await zipExceptionHandler.handler( + line: '', + usesAndroidX: true, + multidexEnabled: true, + project: FakeFlutterProject(), + ); expect(result, equals(GradleBuildStatus.retry)); - expect(globals.fs.file('foo/.gradle/fizz.zip'), exists); + expect(fileSystem.file('foo/.gradle/fizz.zip'), exists); expect( testLogger.errorText, contains( @@ -1194,8 +1297,8 @@ at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)''' expect(testLogger.statusText, ''); }, overrides: { Platform: () => FakePlatform(environment: {'HOME': 'foo/'}), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.empty(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, AnsiTerminal: () => _TestPromptTerminal('n'), BotDetector: () => const FakeBotDetector(false), }); @@ -1217,7 +1320,7 @@ Platform fakePlatform(String name) { ); } -class FakeGradleUtils extends GradleUtils { +class FakeGradleUtils extends Fake implements GradleUtils { @override String getExecutable(FlutterProject project) { return 'gradlew'; @@ -1226,21 +1329,24 @@ class FakeGradleUtils extends GradleUtils { /// Simple terminal that returns the specified string when /// promptForCharInput is called. -class _TestPromptTerminal extends AnsiTerminal { +class _TestPromptTerminal extends Fake implements AnsiTerminal { _TestPromptTerminal(this.promptResult); final String promptResult; @override - Future promptForCharInput(List acceptedCharacters, { - Logger logger, - String prompt, - int defaultChoiceIndex, + bool get stdinHasTerminal => true; + + @override + Future promptForCharInput( + List acceptedCharacters, { + required Logger logger, + String? prompt, + int? defaultChoiceIndex, bool displayAcceptedCharacters = true, }) { return Future.value(promptResult); } - - @override - bool get stdinHasTerminal => true; } + +class FakeFlutterProject extends Fake implements FlutterProject {} diff --git a/packages/flutter_tools/test/general.shard/args_test.dart b/packages/flutter_tools/test/general.shard/args_test.dart index 569006bab8c6e..4725e37d2aa65 100644 --- a/packages/flutter_tools/test/general.shard/args_test.dart +++ b/packages/flutter_tools/test/general.shard/args_test.dart @@ -7,6 +7,7 @@ import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:flutter_tools/executable.dart' as executable; +import 'package:flutter_tools/src/commands/analyze.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; @@ -23,6 +24,12 @@ void main() { verbose: true, ).forEach(runner.addCommand); verifyCommandRunner(runner); + for (final Command command in runner.commands.values) { + if(command.name == 'analyze') { + final AnalyzeCommand analyze = command as AnalyzeCommand; + expect(analyze.allProjectValidators().length, 1); + } + } })); testUsingContext('bool? safe argResults', () async { diff --git a/packages/flutter_tools/test/general.shard/base/build_test.dart b/packages/flutter_tools/test/general.shard/base/build_test.dart index 39161065f8d81..06e33e19a21a2 100644 --- a/packages/flutter_tools/test/general.shard/base/build_test.dart +++ b/packages/flutter_tools/test/general.shard/base/build_test.dart @@ -210,7 +210,6 @@ void main() { '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=$assembly', - '--strip', 'main.dill', ]), kWhichSysctlCommand, @@ -253,6 +252,21 @@ void main() { 'build/foo/App.framework/App', 'build/foo/snapshot_assembly.o', ]), + const FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + 'build/foo/App.framework.dSYM', + 'build/foo/App.framework/App', + ]), + const FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + 'build/foo/App.framework/App', + '-o', + 'build/foo/App.framework/App', + ]), ]); final int genSnapshotExitCode = await snapshotter.build( @@ -285,7 +299,6 @@ void main() { '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=$assembly', - '--strip', '--dwarf-stack-traces', '--save-debugging-info=$debugPath', 'main.dill', @@ -312,6 +325,21 @@ void main() { 'arm64', ...kDefaultClang, ]), + const FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + 'build/foo/App.framework.dSYM', + 'build/foo/App.framework/App', + ]), + const FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + 'build/foo/App.framework/App', + '-o', + 'build/foo/App.framework/App', + ]), ]); final int genSnapshotExitCode = await snapshotter.build( @@ -344,7 +372,6 @@ void main() { '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=$assembly', - '--strip', '--obfuscate', 'main.dill', ]), @@ -370,6 +397,21 @@ void main() { 'arm64', ...kDefaultClang, ]), + const FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + 'build/foo/App.framework.dSYM', + 'build/foo/App.framework/App', + ]), + const FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + 'build/foo/App.framework/App', + '-o', + 'build/foo/App.framework/App', + ]), ]); final int genSnapshotExitCode = await snapshotter.build( @@ -400,7 +442,6 @@ void main() { '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}', - '--strip', 'main.dill', ]), kWhichSysctlCommand, @@ -425,6 +466,21 @@ void main() { 'arm64', ...kDefaultClang, ]), + const FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + 'build/foo/App.framework.dSYM', + 'build/foo/App.framework/App', + ]), + const FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + 'build/foo/App.framework/App', + '-o', + 'build/foo/App.framework/App', + ]), ]); final int genSnapshotExitCode = await snapshotter.build( diff --git a/packages/flutter_tools/test/general.shard/base/file_system_test.dart b/packages/flutter_tools/test/general.shard/base/file_system_test.dart index a3bbad5e198ba..e1bd3c3d73644 100644 --- a/packages/flutter_tools/test/general.shard/base/file_system_test.dart +++ b/packages/flutter_tools/test/general.shard/base/file_system_test.dart @@ -10,6 +10,7 @@ import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/signals.dart'; import 'package:test/fake.dart'; @@ -162,6 +163,21 @@ void main() { signalUnderTest = ProcessSignal(fakeSignal); }); + testWithoutContext('runs shutdown hooks', () async { + final Signals signals = Signals.test(); + final LocalFileSystem localFileSystem = LocalFileSystem.test( + signals: signals, + ); + final Directory temp = localFileSystem.systemTempDirectory; + + expect(temp.existsSync(), isTrue); + expect(localFileSystem.shutdownHooks.registeredHooks, hasLength(1)); + final BufferLogger logger = BufferLogger.test(); + await localFileSystem.shutdownHooks.runShutdownHooks(logger); + expect(temp.existsSync(), isFalse); + expect(logger.traceText, contains('Running 1 shutdown hook')); + }); + testWithoutContext('deletes system temp entry on a fatal signal', () async { final Completer completer = Completer(); final Signals signals = Signals.test(); diff --git a/packages/flutter_tools/test/general.shard/base/os_test.dart b/packages/flutter_tools/test/general.shard/base/os_test.dart index b5c4da84fffe4..5d6765cc8c733 100644 --- a/packages/flutter_tools/test/general.shard/base/os_test.dart +++ b/packages/flutter_tools/test/general.shard/base/os_test.dart @@ -219,7 +219,7 @@ void main() { final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'macos')); - expect(utils.hostPlatform, HostPlatform.darwin_arm); + expect(utils.hostPlatform, HostPlatform.darwin_arm64); }); testWithoutContext('macOS 11 x86', () async { @@ -335,7 +335,7 @@ void main() { final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'macos')); - expect(utils.name, 'product version build darwin-arm'); + expect(utils.name, 'product version build darwin-arm64'); }); testWithoutContext('macOS ARM on Rosetta name', () async { @@ -385,7 +385,7 @@ void main() { final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'macos')); - expect(utils.name, 'product version build darwin-arm (Rosetta)'); + expect(utils.name, 'product version build darwin-arm64 (Rosetta)'); }); testWithoutContext('macOS x86 name', () async { diff --git a/packages/flutter_tools/test/general.shard/base/process_test.dart b/packages/flutter_tools/test/general.shard/base/process_test.dart index 208ceb22e2fc4..51e6c2d1020b4 100644 --- a/packages/flutter_tools/test/general.shard/base/process_test.dart +++ b/packages/flutter_tools/test/general.shard/base/process_test.dart @@ -42,13 +42,13 @@ void main() { int i = 1; int? cleanup; - final ShutdownHooks shutdownHooks = ShutdownHooks(logger: BufferLogger.test()); + final ShutdownHooks shutdownHooks = ShutdownHooks(); shutdownHooks.addShutdownHook(() async { cleanup = i++; }); - await shutdownHooks.runShutdownHooks(); + await shutdownHooks.runShutdownHooks(BufferLogger.test()); expect(cleanup, 1); }); diff --git a/packages/flutter_tools/test/general.shard/build_info_test.dart b/packages/flutter_tools/test/general.shard/build_info_test.dart index 53a4e2578b581..e628b7b00220d 100644 --- a/packages/flutter_tools/test/general.shard/build_info_test.dart +++ b/packages/flutter_tools/test/general.shard/build_info_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -99,6 +100,45 @@ void main() { expect(getNameForTargetPlatform(TargetPlatform.android), isNot(contains('ios'))); }); + testWithoutContext('defaultIOSArchsForEnvironment', () { + expect(defaultIOSArchsForEnvironment( + EnvironmentType.physical, + Artifacts.test(localEngine: 'ios_debug_unopt'), + ).single, DarwinArch.arm64); + + expect(defaultIOSArchsForEnvironment( + EnvironmentType.simulator, + Artifacts.test(localEngine: 'ios_debug_sim_unopt'), + ).single, DarwinArch.x86_64); + + expect(defaultIOSArchsForEnvironment( + EnvironmentType.simulator, + Artifacts.test(localEngine: 'ios_debug_sim_unopt_arm64'), + ).single, DarwinArch.arm64); + + expect(defaultIOSArchsForEnvironment( + EnvironmentType.physical, Artifacts.test(), + ).single, DarwinArch.arm64); + + expect(defaultIOSArchsForEnvironment( + EnvironmentType.simulator, Artifacts.test(), + ), [ DarwinArch.x86_64, DarwinArch.arm64 ]); + }); + + testWithoutContext('defaultMacOSArchsForEnvironment', () { + expect(defaultMacOSArchsForEnvironment( + Artifacts.test(localEngine: 'host_debug_unopt'), + ).single, DarwinArch.x86_64); + + expect(defaultMacOSArchsForEnvironment( + Artifacts.test(localEngine: 'host_debug_unopt_arm64'), + ).single, DarwinArch.arm64); + + expect(defaultMacOSArchsForEnvironment( + Artifacts.test(), + ), [ DarwinArch.x86_64, DarwinArch.arm64 ]); + }); + testWithoutContext('getIOSArchForName on Darwin arches', () { expect(getIOSArchForName('armv7'), DarwinArch.armv7); expect(getIOSArchForName('arm64'), DarwinArch.arm64); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 03c198496a2d4..422890aff3e1a 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -477,7 +477,6 @@ void main() { '--deterministic', kAssemblyAot, '--assembly=$build/arm64/snapshot_assembly.S', - '--strip', '$build/app.dill', ]), FakeCommand(command: [ @@ -520,6 +519,21 @@ void main() { '$build/arm64/App.framework/App', '$build/arm64/snapshot_assembly.o', ]), + FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + '$build/arm64/App.framework.dSYM', + '$build/arm64/App.framework/App', + ]), + FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + '$build/arm64/App.framework/App', + '-o', + '$build/arm64/App.framework/App', + ]), FakeCommand(command: [ 'lipo', '$build/arm64/App.framework/App', @@ -553,7 +567,6 @@ void main() { '--trace-precompiler-to=code_size_1/trace.arm64.json', kAssemblyAot, '--assembly=$build/arm64/snapshot_assembly.S', - '--strip', '$build/app.dill', ]), FakeCommand(command: [ @@ -596,6 +609,21 @@ void main() { '$build/arm64/App.framework/App', '$build/arm64/snapshot_assembly.o', ]), + FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + '$build/arm64/App.framework.dSYM', + '$build/arm64/App.framework/App', + ]), + FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + '$build/arm64/App.framework/App', + '-o', + '$build/arm64/App.framework/App', + ]), FakeCommand(command: [ 'lipo', '$build/arm64/App.framework/App', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index b9412d436ab69..cd2d81a3cad84 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -239,6 +239,14 @@ void main() { .childFile('App') .createSync(recursive: true); + // Input dSYM + environment.buildDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App') + .createSync(recursive: true); final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); final File frameworkDirectoryBinary = frameworkDirectory.childFile('App'); @@ -257,6 +265,12 @@ void main() { expect(frameworkDirectoryBinary, exists); expect(frameworkDirectory.childFile('Info.plist'), exists); + expect(environment.outputDir + .childDirectory('App.framework.dSYM') + .childDirectory('Contents') + .childDirectory('Resources') + .childDirectory('DWARF') + .childFile('App'), exists); final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); expect(assetDirectory.childFile('kernel_blob.bin'), isNot(exists)); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index 909f5fe27ab67..c43454d5b15e0 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart @@ -295,6 +295,28 @@ void main() { ProcessManager: () => processManager, }); + testUsingContext('release macOS application creates App.framework.dSYM', () async { + fileSystem.file('bin/cache/artifacts/engine/darwin-x64/vm_isolate_snapshot.bin') + .createSync(recursive: true); + fileSystem.file('bin/cache/artifacts/engine/darwin-x64/isolate_snapshot.bin') + .createSync(recursive: true); + fileSystem.file('${environment.buildDir.path}/App.framework/App') + .createSync(recursive: true); + fileSystem.file('${environment.buildDir.path}/App.framework.dSYM/Contents/Resources/DWARF/App') + .createSync(recursive: true); + + await const ReleaseMacOSBundleFlutterAssets() + .build(environment..defines[kBuildMode] = 'release'); + + expect(fileSystem.file( + 'App.framework.dSYM/Contents/Resources/DWARF/App'), + exists, + ); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); + testUsingContext('release/profile macOS application updates when App.framework updates', () async { fileSystem.file('bin/cache/artifacts/engine/darwin-x64/vm_isolate_snapshot.bin') .createSync(recursive: true); @@ -415,13 +437,20 @@ void main() { environment.defines[kDarwinArchs] = 'arm64 x86_64'; environment.defines[kBuildMode] = 'release'; + // Input dSYMs need to exist for `lipo` to combine them + environment.buildDir + .childFile('arm64/App.framework.dSYM/Contents/Resources/DWARF/App') + .createSync(recursive: true); + environment.buildDir + .childFile('x86_64/App.framework.dSYM/Contents/Resources/DWARF/App') + .createSync(recursive: true); + processManager.addCommands([ FakeCommand(command: [ 'Artifact.genSnapshot.TargetPlatform.darwin.release_arm64', '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=${environment.buildDir.childFile('arm64/snapshot_assembly.S').path}', - '--strip', environment.buildDir.childFile('app.dill').path, ]), FakeCommand(command: [ @@ -429,7 +458,6 @@ void main() { '--deterministic', '--snapshot_kind=app-aot-assembly', '--assembly=${environment.buildDir.childFile('x86_64/snapshot_assembly.S').path}', - '--strip', environment.buildDir.childFile('app.dill').path, ]), FakeCommand(command: [ @@ -458,6 +486,36 @@ void main() { '-o', environment.buildDir.childFile('x86_64/App.framework/App').path, environment.buildDir.childFile('x86_64/snapshot_assembly.o').path, ]), + FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + environment.buildDir.childFile('arm64/App.framework.dSYM').path, + environment.buildDir.childFile('arm64/App.framework/App').path, + ]), + FakeCommand(command: [ + 'xcrun', + 'dsymutil', + '-o', + environment.buildDir.childFile('x86_64/App.framework.dSYM').path, + environment.buildDir.childFile('x86_64/App.framework/App').path, + ]), + FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + environment.buildDir.childFile('arm64/App.framework/App').path, + '-o', + environment.buildDir.childFile('arm64/App.framework/App').path, + ]), + FakeCommand(command: [ + 'xcrun', + 'strip', + '-S', + environment.buildDir.childFile('x86_64/App.framework/App').path, + '-o', + environment.buildDir.childFile('x86_64/App.framework/App').path, + ]), FakeCommand(command: [ 'lipo', environment.buildDir.childFile('arm64/App.framework/App').path, @@ -466,6 +524,14 @@ void main() { '-output', environment.buildDir.childFile('App.framework/App').path, ]), + FakeCommand(command: [ + 'lipo', + environment.buildDir.childFile('arm64/App.framework.dSYM/Contents/Resources/DWARF/App').path, + environment.buildDir.childFile('x86_64/App.framework.dSYM/Contents/Resources/DWARF/App').path, + '-create', + '-output', + environment.buildDir.childFile('App.framework.dSYM/Contents/Resources/DWARF/App').path, + ]), ]); await const CompileMacOSFramework().build(environment); diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index 18684fb90d11c..56c80613febac 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -566,9 +566,9 @@ void main() { cache.includeAllPlatforms = true; expect(artifacts.getBinaryDirs(), >[ - ['darwin-x64', 'darwin-x64/font-subset.zip'], // arm64 macOS hosts are not supported now + ['darwin-x64', 'darwin-arm64/font-subset.zip'], ['linux-arm64', 'linux-arm64/font-subset.zip'], - ['windows-x64', 'windows-x64/font-subset.zip'], // arm64 macOS hosts are not supported now + ['windows-x64', 'windows-x64/font-subset.zip'], // arm64 windows hosts are not supported now ]); }); diff --git a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart index 52f1511dabb57..8e20fe9eff62b 100644 --- a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart @@ -36,7 +36,6 @@ void main() { 'sdkroot/', '--incremental', '--target=flutter', - '--debugger-module-names', '--experimental-emit-debug-metadata', '--output-dill', '/build/', diff --git a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart index fe770b7fdac4a..4f6ae0ef3bbe5 100644 --- a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart @@ -120,6 +120,30 @@ void main() { expect(adapter.flutterRequests, contains('app.stop')); }); + + test('does not call "app.stop" on terminateRequest if app was not started', () async { + final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter( + fileSystem: MemoryFileSystem.test(style: fsStyle), + platform: platform, + simulateAppStarted: false, + ); + + final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( + cwd: '/project', + program: 'foo.dart', + ); + + await adapter.configurationDoneRequest(MockRequest(), null, () {}); + final Completer launchCompleter = Completer(); + await adapter.launchRequest(MockRequest(), args, launchCompleter.complete); + await launchCompleter.future; + + final Completer terminateCompleter = Completer(); + await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete); + await terminateCompleter.future; + + expect(adapter.flutterRequests, isNot(contains('app.stop'))); + }); }); group('attachRequest', () { diff --git a/packages/flutter_tools/test/general.shard/dap/mocks.dart b/packages/flutter_tools/test/general.shard/dap/mocks.dart index fb44b77c6e319..2cb8475b8170f 100644 --- a/packages/flutter_tools/test/general.shard/dap/mocks.dart +++ b/packages/flutter_tools/test/general.shard/dap/mocks.dart @@ -15,6 +15,7 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { factory MockFlutterDebugAdapter({ required FileSystem fileSystem, required Platform platform, + bool simulateAppStarted = true, }) { final StreamController> stdinController = StreamController>(); final StreamController> stdoutController = StreamController>(); @@ -26,6 +27,7 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { channel, fileSystem: fileSystem, platform: platform, + simulateAppStarted: simulateAppStarted, ); } @@ -35,10 +37,12 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { ByteStreamServerChannel channel, { required FileSystem fileSystem, required Platform platform, + this.simulateAppStarted = true, }) : super(channel, fileSystem: fileSystem, platform: platform); final StreamSink> stdin; final Stream> stdout; + final bool simulateAppStarted; late String executable; late List processArgs; @@ -57,7 +61,10 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter { // Pretend we launched the app and got the app.started event so that // launchRequest will complete. - appStartedCompleter.complete(); + if (simulateAppStarted) { + appId = 'TEST'; + appStartedCompleter.complete(); + } } @override diff --git a/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart b/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart index b2dcb078dc435..b6471f03e6a8e 100644 --- a/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart +++ b/packages/flutter_tools/test/general.shard/drive/drive_service_test.dart @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/base/dds.dart'; +import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -19,7 +18,6 @@ import 'package:flutter_tools/src/drive/drive_service.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:meta/meta.dart'; import 'package:package_config/package_config_types.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -425,10 +423,10 @@ void main() { } FlutterDriverService setUpDriverService({ - Logger logger, - ProcessManager processManager, - FlutterVmService vmService, - DevtoolsLauncher devtoolsLauncher, + Logger? logger, + ProcessManager? processManager, + FlutterVmService? vmService, + DevtoolsLauncher? devtoolsLauncher, }) { logger ??= BufferLogger.test(); return FlutterDriverService( @@ -441,14 +439,14 @@ FlutterDriverService setUpDriverService({ dartSdkPath: 'dart', devtoolsLauncher: devtoolsLauncher ?? FakeDevtoolsLauncher(), vmServiceConnector: (Uri httpUri, { - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - Object compression, - Device device, - @required Logger logger, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + io.CompressionOptions compression = io.CompressionOptions.compressionDefault, + Device? device, + required Logger logger, }) async { assert(logger != null); if (httpUri.scheme != 'http') { @@ -457,7 +455,7 @@ FlutterDriverService setUpDriverService({ if (httpUri.path.endsWith('/ws')) { fail('Expected HTTP uri to not contain `/ws`, found $httpUri'); } - return vmService; + return vmService!; } ); } @@ -470,8 +468,8 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFa @override Future getPackageForPlatform( TargetPlatform platform, { - BuildInfo buildInfo, - File applicationBinary, + BuildInfo? buildInfo, + File? applicationBinary, }) async => applicationPackage; } @@ -505,21 +503,21 @@ class FakeDevice extends Fake implements Device { @override Future getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) async => NoOpDeviceLogReader('test'); @override Future startApp( covariant ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + String? mainPath, + String? route, + required DebuggingOptions debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool ipv6 = false, - String userIdentifier, - }) async { + String? userIdentifier, + }) async { if (failOnce) { failOnce = false; return LaunchResult.failed(); @@ -528,13 +526,13 @@ class FakeDevice extends Fake implements Device { } @override - Future stopApp(covariant ApplicationPackage app, {String userIdentifier}) async { + Future stopApp(covariant ApplicationPackage app, {String? userIdentifier}) async { didStopApp = true; return true; } @override - Future uninstallApp(covariant ApplicationPackage app, {String userIdentifier}) async { + Future uninstallApp(covariant ApplicationPackage app, {String? userIdentifier}) async { didUninstallApp = true; return true; } @@ -555,10 +553,10 @@ class FakeDartDevelopmentService extends Fake implements DartDevelopmentService @override Future startDartDevelopmentService( Uri observatoryUri, { - @required Logger logger, - int hostPort, - bool ipv6, - bool disableServiceAuthCodes, + required Logger logger, + int? hostPort, + bool? ipv6, + bool? disableServiceAuthCodes, bool cacheStartupProfile = false, }) async { started = true; @@ -575,7 +573,7 @@ class FakeDevtoolsLauncher extends Fake implements DevtoolsLauncher { final Completer _processStarted = Completer(); @override - Future launch(Uri vmServiceUri, {List additionalArguments}) { + Future launch(Uri vmServiceUri, {List? additionalArguments}) { _processStarted.complete(); return Completer().future; } diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart index c8e20365594f1..569ff1699d663 100644 --- a/packages/flutter_tools/test/general.shard/features_test.dart +++ b/packages/flutter_tools/test/general.shard/features_test.dart @@ -384,5 +384,20 @@ void main() { }); } + // Custom devices on all channels + for (final String channel in ['master', 'beta', 'stable']) { + testWithoutContext('Custom devices are enabled with flag on $channel', () { + final FeatureFlags featureFlags = createFlags(channel); + testConfig.setValue('enable-custom-devices', true); + expect(featureFlags.areCustomDevicesEnabled, true); + }); + + testWithoutContext('Custom devices are enabled with environment variable on $channel', () { + final FeatureFlags featureFlags = createFlags(channel); + platform.environment = {'FLUTTER_CUSTOM_DEVICES': 'true'}; + expect(featureFlags.areCustomDevicesEnabled, true); + }); + } + }); } diff --git a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart index 68362339c8368..68e457d65b4c7 100644 --- a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart @@ -97,7 +97,9 @@ void main() { icudtlPath: 'ghi', platformPluginRegistration: (FlutterPlatform platform) { capturedPlatform = platform; - }); + }, + uriConverter: (String input) => '$input/test', + ); expect(identical(capturedPlatform, flutterPlatform), equals(true)); expect(flutterPlatform.shellPath, equals('abc')); @@ -113,6 +115,7 @@ void main() { expect(flutterPlatform.updateGoldens, equals(true)); expect(flutterPlatform.testAssetDirectory, '/build/test'); expect(flutterPlatform.icudtlPath, equals('ghi')); + expect(flutterPlatform.uriConverter?.call('hello'), 'hello/test'); }); }); } diff --git a/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart b/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart index 454cbab71ba0a..8edeafafb17f8 100644 --- a/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_tester_device_test.dart @@ -46,69 +46,12 @@ void main() { processManager: processManager, enableObservatory: enableObservatory, dartEntrypointArgs: dartEntrypointArgs, + uriConverter: (String input) => '$input/converted', ); - testUsingContext('runs in Rosetta on arm64 Mac', () async { - final FakeProcessManager processManager = FakeProcessManager.empty(); - final FlutterTesterTestDevice device = TestFlutterTesterDevice( - platform: FakePlatform(operatingSystem: 'macos'), - fileSystem: fileSystem, - processManager: processManager, - enableObservatory: false, - dartEntrypointArgs: const [], - ); - processManager.addCommands([ - const FakeCommand( - command: [ - 'which', - 'sysctl', - ], - ), - const FakeCommand( - command: [ - 'sysctl', - 'hw.optional.arm64', - ], - stdout: 'hw.optional.arm64: 1', - ), - FakeCommand(command: const [ - '/usr/bin/arch', - '-x86_64', - '/', - '--disable-observatory', - '--ipv6', - '--enable-checked-mode', - '--verify-entry-points', - '--enable-software-rendering', - '--skia-deterministic-rendering', - '--enable-dart-profiling', - '--non-interactive', - '--use-test-fonts', - '--disable-asset-fonts', - '--packages=.dart_tool/package_config.json', - 'example.dill', - ], environment: { - 'FLUTTER_TEST': 'true', - 'FONTCONFIG_FILE': device.fontConfigManager.fontConfigFile.path, - 'SERVER_PORT': '0', - 'APP_NAME': '', - }), - ]); - await device.start('example.dill'); - expect(processManager, hasNoRemainingExpectations); - }); - group('The FLUTTER_TEST environment variable is passed to the test process', () { setUp(() { - processManager = FakeProcessManager.list([ - const FakeCommand( - command: [ - 'uname', - '-m', - ], - stdout: 'x86_64', - ), - ]); + processManager = FakeProcessManager.list([]); device = createDevice(); fileSystem @@ -175,13 +118,6 @@ void main() { group('Dart Entrypoint Args', () { setUp(() { processManager = FakeProcessManager.list([ - const FakeCommand( - command: [ - 'uname', - '-m', - ], - stdout: 'x86_64', - ), const FakeCommand( command: [ '/', @@ -217,13 +153,6 @@ void main() { group('DDS', () { setUp(() { processManager = FakeProcessManager.list([ - const FakeCommand( - command: [ - 'uname', - '-m', - ], - stdout: 'x86_64', - ), const FakeCommand( command: [ '/', @@ -254,6 +183,18 @@ void main() { final Uri uri = await (device as TestFlutterTesterDevice).ddsServiceUriFuture(); expect(uri.port, 1234); }); + + testUsingContext('sets up UriConverter from context', () async { + await device.start('example.dill'); + await device.observatoryUri; + + final FakeDartDevelopmentService dds = (device as TestFlutterTesterDevice).dds + as FakeDartDevelopmentService; + final String? result = dds + .uriConverter + ?.call('test'); + expect(result, 'test/converted'); + }); }); } @@ -267,6 +208,7 @@ class TestFlutterTesterDevice extends FlutterTesterTestDevice { required super.processManager, required super.enableObservatory, required List dartEntrypointArgs, + required UriConverter uriConverter, }) : super( id: 999, shellPath: '/', @@ -287,16 +229,26 @@ class TestFlutterTesterDevice extends FlutterTesterTestDevice { icudtlPath: null, compileExpression: null, fontConfigManager: FontConfigManager(), + uriConverter: uriConverter, ); + late DartDevelopmentService dds; final Completer _ddsServiceUriCompleter = Completer(); Future ddsServiceUriFuture() => _ddsServiceUriCompleter.future; @override - Future startDds(Uri uri) async { + Future startDds( + Uri uri, { + UriConverter? uriConverter, + }) async { _ddsServiceUriCompleter.complete(uri); - return FakeDartDevelopmentService(Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}'), Uri.parse('http://localhost:8080')); + dds = FakeDartDevelopmentService( + Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}'), + Uri.parse('http://localhost:8080'), + uriConverter: uriConverter, + ); + return dds; } @override @@ -307,9 +259,10 @@ class TestFlutterTesterDevice extends FlutterTesterTestDevice { } class FakeDartDevelopmentService extends Fake implements DartDevelopmentService { - FakeDartDevelopmentService(this.uri, this.original); + FakeDartDevelopmentService(this.uri, this.original, {this.uriConverter}); final Uri original; + final UriConverter? uriConverter; @override final Uri uri; diff --git a/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart b/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart index abc5ee704f7af..1900c2648e8bd 100644 --- a/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart @@ -197,7 +197,7 @@ void main() { testWithoutContext('target platform display name on ARM', () async { final FakeOperatingSystemUtils fakeOperatingSystemUtils = FakeOperatingSystemUtils(); - fakeOperatingSystemUtils.hostPlatform = HostPlatform.darwin_arm; + fakeOperatingSystemUtils.hostPlatform = HostPlatform.darwin_arm64; final MacOSDevice device = MacOSDevice( fileSystem: MemoryFileSystem.test(), logger: BufferLogger.test(), diff --git a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart index 896303f381b60..6b8a2eb85e4cd 100644 --- a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart @@ -32,7 +32,7 @@ void main() { logger: BufferLogger.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm), + operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64), iosWorkflow: FakeIOSWorkflow(canListDevices: true), ); @@ -45,7 +45,7 @@ void main() { logger: BufferLogger.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm), + operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64), iosWorkflow: FakeIOSWorkflow(canListDevices: true), ); expect(discoverer.supportsPlatform, isTrue); @@ -77,7 +77,7 @@ void main() { logger: BufferLogger.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm), + operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64), iosWorkflow: FakeIOSWorkflow(canListDevices: false), ); expect(discoverer.supportsPlatform, isTrue); @@ -93,7 +93,7 @@ void main() { logger: BufferLogger.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm), + operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64), iosWorkflow: FakeIOSWorkflow(canListDevices: true), ); expect(discoverer.supportsPlatform, isTrue); @@ -116,7 +116,7 @@ void main() { logger: BufferLogger.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm), + operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64), ); expect(device.id, 'designed-for-ipad'); expect(await device.isLocalEmulator, isFalse); diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 64a757e90fe64..4900dc1b9dec3 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -32,13 +30,6 @@ void main() { group('Project', () { group('construction', () { - _testInMemory('fails on null directory', () async { - expect( - () => FlutterProject.fromDirectory(null), - throwsAssertionError, - ); - }); - testWithoutContext('invalid utf8 throws a tool exit', () { final FileSystem fileSystem = MemoryFileSystem.test(); final FlutterProjectFactory projectFactory = FlutterProjectFactory( @@ -226,7 +217,8 @@ void main() { // v1 embedding, as opposed to having . - project.checkForDeprecation(deprecationBehavior: DeprecationBehavior.none); + // Default is "DeprecationBehavior.none" + project.checkForDeprecation(); expect(testLogger.statusText, isEmpty); }); _testInMemory('Android project not on v2 embedding ignore continues', () async { @@ -350,8 +342,8 @@ void main() { final FlutterManifest manifest = FlutterManifest.createFromString(''' name: test version: 1.0.0+3 - ''', logger: BufferLogger.test()); - final FlutterProject project = FlutterProject(fileSystem.systemTempDirectory,manifest,manifest); + ''', logger: BufferLogger.test())!; + final FlutterProject project = FlutterProject(fileSystem.systemTempDirectory, manifest, manifest); final Map versionInfo = jsonDecode(project.getVersionInfo()) as Map; expect(versionInfo['app_name'],'test'); expect(versionInfo['version'],'1.0.0'); @@ -397,9 +389,9 @@ void main() { }); group('language', () { - XcodeProjectInterpreter xcodeProjectInterpreter; - MemoryFileSystem fs; - FlutterProjectFactory flutterProjectFactory; + late XcodeProjectInterpreter xcodeProjectInterpreter; + late MemoryFileSystem fs; + late FlutterProjectFactory flutterProjectFactory; setUp(() { fs = MemoryFileSystem.test(); xcodeProjectInterpreter = XcodeProjectInterpreter.test(processManager: FakeProcessManager.any()); @@ -434,14 +426,14 @@ apply plugin: 'kotlin-android' }); group('product bundle identifier', () { - MemoryFileSystem fs; - FakePlistParser testPlistUtils; - MockXcodeProjectInterpreter mockXcodeProjectInterpreter; - FlutterProjectFactory flutterProjectFactory; + late MemoryFileSystem fs; + late FakePlistParser testPlistUtils; + late FakeXcodeProjectInterpreter xcodeProjectInterpreter; + late FlutterProjectFactory flutterProjectFactory; setUp(() { fs = MemoryFileSystem.test(); testPlistUtils = FakePlistParser(); - mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); + xcodeProjectInterpreter = FakeXcodeProjectInterpreter(); flutterProjectFactory = FlutterProjectFactory( fileSystem: fs, logger: logger, @@ -453,7 +445,7 @@ apply plugin: 'kotlin-android' FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), PlistParser: () => testPlistUtils, - XcodeProjectInterpreter: () => mockXcodeProjectInterpreter, + XcodeProjectInterpreter: () => xcodeProjectInterpreter, FlutterProjectFactory: () => flutterProjectFactory, }); } @@ -466,16 +458,18 @@ apply plugin: 'kotlin-android' testWithMocks('from build settings, if no plist', () async { final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); - mockXcodeProjectInterpreter.buildSettings = { + xcodeProjectInterpreter.buildSettings = { 'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', }; - mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); expect(await project.ios.productBundleIdentifier(null), 'io.flutter.someProject'); }); testWithMocks('from project file, if no plist or build settings', () async { final FlutterProject project = await someProject(); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); + addIosProjectFile(project.directory, projectFileContent: () { return projectFileWithBundleId('io.flutter.someProject'); }); @@ -492,10 +486,10 @@ apply plugin: 'kotlin-android' testWithMocks('from build settings and plist, if default variable', () async { final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); - mockXcodeProjectInterpreter.buildSettings = { + xcodeProjectInterpreter.buildSettings = { 'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', }; - mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); testPlistUtils.setProperty('CFBundleIdentifier', r'$(PRODUCT_BUNDLE_IDENTIFIER)'); expect(await project.ios.productBundleIdentifier(null), 'io.flutter.someProject'); @@ -505,11 +499,11 @@ apply plugin: 'kotlin-android' final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); project.ios.defaultHostInfoPlist.createSync(recursive: true); - mockXcodeProjectInterpreter.buildSettings = { + xcodeProjectInterpreter.buildSettings = { 'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', 'SUFFIX': 'suffix', }; - mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); testPlistUtils.setProperty('CFBundleIdentifier', r'$(PRODUCT_BUNDLE_IDENTIFIER).$(SUFFIX)'); expect(await project.ios.productBundleIdentifier(null), 'io.flutter.someProject.suffix'); @@ -518,7 +512,7 @@ apply plugin: 'kotlin-android' testWithMocks('fails with no flavor and defined schemes', () async { final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); - mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['free', 'paid'], logger); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['free', 'paid'], logger); await expectToolExitLater( project.ios.productBundleIdentifier(null), @@ -529,10 +523,10 @@ apply plugin: 'kotlin-android' testWithMocks('handles case insensitive flavor', () async { final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); - mockXcodeProjectInterpreter.buildSettings = { + xcodeProjectInterpreter.buildSettings = { 'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', }; - mockXcodeProjectInterpreter.xcodeProjectInfo =XcodeProjectInfo([], [], ['Free'], logger); + xcodeProjectInterpreter.xcodeProjectInfo =XcodeProjectInfo([], [], ['Free'], logger); const BuildInfo buildInfo = BuildInfo(BuildMode.debug, 'free', treeShakeIcons: false); expect(await project.ios.productBundleIdentifier(buildInfo), 'io.flutter.someProject'); @@ -541,7 +535,7 @@ apply plugin: 'kotlin-android' testWithMocks('fails with flavor and default schemes', () async { final FlutterProject project = await someProject(); project.ios.xcodeProject.createSync(); - mockXcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); const BuildInfo buildInfo = BuildInfo(BuildMode.debug, 'free', treeShakeIcons: false); await expectToolExitLater( @@ -552,6 +546,7 @@ apply plugin: 'kotlin-android' testWithMocks('empty surrounded by quotes', () async { final FlutterProject project = await someProject(); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); addIosProjectFile(project.directory, projectFileContent: () { return projectFileWithBundleId('', qualifier: '"'); }); @@ -560,6 +555,7 @@ apply plugin: 'kotlin-android' testWithMocks('surrounded by double quotes', () async { final FlutterProject project = await someProject(); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); addIosProjectFile(project.directory, projectFileContent: () { return projectFileWithBundleId('io.flutter.someProject', qualifier: '"'); }); @@ -568,6 +564,7 @@ apply plugin: 'kotlin-android' testWithMocks('surrounded by single quotes', () async { final FlutterProject project = await someProject(); + xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); addIosProjectFile(project.directory, projectFileContent: () { return projectFileWithBundleId('io.flutter.someProject', qualifier: "'"); }); @@ -576,11 +573,11 @@ apply plugin: 'kotlin-android' }); group('application bundle name', () { - MemoryFileSystem fs; - MockXcodeProjectInterpreter mockXcodeProjectInterpreter; + late MemoryFileSystem fs; + late FakeXcodeProjectInterpreter mockXcodeProjectInterpreter; setUp(() { fs = MemoryFileSystem.test(); - mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); + mockXcodeProjectInterpreter = FakeXcodeProjectInterpreter(); }); testUsingContext('app product name defaults to Runner.app', () async { @@ -681,14 +678,14 @@ apply plugin: 'kotlin-android' }); }); group('watch companion', () { - MemoryFileSystem fs; - FakePlistParser testPlistParser; - MockXcodeProjectInterpreter mockXcodeProjectInterpreter; - FlutterProjectFactory flutterProjectFactory; + late MemoryFileSystem fs; + late FakePlistParser testPlistParser; + late FakeXcodeProjectInterpreter mockXcodeProjectInterpreter; + late FlutterProjectFactory flutterProjectFactory; setUp(() { fs = MemoryFileSystem.test(); testPlistParser = FakePlistParser(); - mockXcodeProjectInterpreter = MockXcodeProjectInterpreter(); + mockXcodeProjectInterpreter = FakeXcodeProjectInterpreter(); flutterProjectFactory = FlutterProjectFactory( fileSystem: fs, logger: logger, @@ -697,7 +694,7 @@ apply plugin: 'kotlin-android' testUsingContext('cannot find bundle identifier', () async { final FlutterProject project = await someProject(); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isFalse); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isFalse); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -716,7 +713,7 @@ apply plugin: 'kotlin-android' testUsingContext('no Info.plist in target', () async { final FlutterProject project = await someProject(); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isFalse); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isFalse); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -729,7 +726,7 @@ apply plugin: 'kotlin-android' final FlutterProject project = await someProject(); project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isFalse); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isFalse); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -743,7 +740,7 @@ apply plugin: 'kotlin-android' project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true); testPlistParser.setProperty('WKCompanionAppBundleIdentifier', 'io.flutter.someOTHERproject'); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isFalse); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isFalse); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -758,7 +755,7 @@ apply plugin: 'kotlin-android' project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true); testPlistParser.setProperty('WKCompanionAppBundleIdentifier', 'io.flutter.someProject'); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isTrue); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isTrue); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -776,7 +773,7 @@ apply plugin: 'kotlin-android' project.ios.hostAppRoot.childDirectory('WatchTarget').childFile('Info.plist').createSync(recursive: true); testPlistParser.setProperty('WKCompanionAppBundleIdentifier', r'$(PRODUCT_BUNDLE_IDENTIFIER)'); - expect(await project.ios.containsWatchCompanion(['WatchTarget'], null, '123'), isTrue); + expect(await project.ios.containsWatchCompanion(['WatchTarget'], BuildInfo.debug, '123'), isTrue); }, overrides: { FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -789,7 +786,7 @@ apply plugin: 'kotlin-android' } Future someProject({ - String androidManifestOverride, + String? androidManifestOverride, bool includePubspec = false, }) async { final Directory directory = globals.fs.directory('some_project'); @@ -934,7 +931,7 @@ void _testInMemory(String description, Future Function() testMethod) { ), FlutterProjectFactory: () => FlutterProjectFactory( fileSystem: testFileSystem, - logger: globals.logger ?? BufferLogger.test(), + logger: globals.logger, ), }, ); @@ -963,7 +960,7 @@ void expectNotExists(FileSystemEntity entity) { expect(entity.existsSync(), isFalse); } -void addIosProjectFile(Directory directory, {String Function() projectFileContent}) { +void addIosProjectFile(Directory directory, {required String Function() projectFileContent}) { directory .childDirectory('ios') .childDirectory('Runner.xcodeproj') @@ -972,7 +969,7 @@ void addIosProjectFile(Directory directory, {String Function() projectFileConten ..writeAsStringSync(projectFileContent()); } -void addAndroidGradleFile(Directory directory, { String Function() gradleFileContent }) { +void addAndroidGradleFile(Directory directory, { required String Function() gradleFileContent }) { directory .childDirectory('android') .childDirectory('app') @@ -1016,7 +1013,7 @@ flutter: something_else: '''; -String projectFileWithBundleId(String id, {String qualifier}) { +String projectFileWithBundleId(String id, {String? qualifier}) { return ''' 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; @@ -1066,20 +1063,20 @@ File androidPluginRegistrant(Directory parent) { .childFile('GeneratedPluginRegistrant.java'); } -class MockXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { +class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { Map buildSettings = {}; - XcodeProjectInfo xcodeProjectInfo; + late XcodeProjectInfo xcodeProjectInfo; @override Future> getBuildSettings(String projectPath, { - XcodeProjectBuildContext buildContext, + XcodeProjectBuildContext? buildContext, Duration timeout = const Duration(minutes: 1), }) async { return buildSettings; } @override - Future getInfo(String projectPath, {String projectFilename}) async { + Future getInfo(String projectPath, {String? projectFilename}) async { return xcodeProjectInfo; } diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index e7513b5b4232d..b37f4844a2edb 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:dds/dds.dart' as dds; @@ -35,7 +33,6 @@ import 'package:flutter_tools/src/run_cold.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -157,12 +154,12 @@ const FakeVmServiceRequest evictShader = FakeVmServiceRequest( final Uri testUri = Uri.parse('foo://bar'); void main() { - Testbed testbed; - FakeFlutterDevice flutterDevice; - FakeDevFS devFS; - ResidentRunner residentRunner; - FakeDevice device; - FakeVmServiceHost fakeVmServiceHost; + late Testbed testbed; + late FakeFlutterDevice flutterDevice; + late FakeDevFS devFS; + late ResidentRunner residentRunner; + late FakeDevice device; + FakeVmServiceHost? fakeVmServiceHost; setUp(() { testbed = Testbed(setup: () { @@ -197,7 +194,7 @@ void main() { ]); final Completer futureConnectionInfo = Completer.sync(); final Completer futureAppStart = Completer.sync(); - final Future result = residentRunner.attach( + final Future result = residentRunner.attach( appStartedCompleter: futureAppStart, connectionInfoCompleter: futureConnectionInfo, enableDevTools: true, @@ -208,7 +205,7 @@ void main() { expect(futureConnectionInfo.isCompleted, true); expect((await connectionInfo).baseUri, 'foo://bar'); expect(futureAppStart.isCompleted, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner suppresses errors for the initial compilation', () => testbed.run(() async { @@ -233,7 +230,7 @@ void main() { expect(await residentRunner.run(enableDevTools: true), 0); expect(residentCompiler.didSuppressErrors, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); // Regression test for https://github.com/flutter/flutter/issues/60613 @@ -325,7 +322,7 @@ void main() { expect(await residentRunner.run(enableDevTools: true), 0); expect(residentCompiler.didSuppressErrors, false); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner can attach to device successfully with --fast-start', () => testbed.run(() async { @@ -335,14 +332,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakeUnpausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), listViews, const FakeVmServiceRequest( @@ -382,7 +379,7 @@ void main() { ); final Completer futureConnectionInfo = Completer.sync(); final Completer futureAppStart = Completer.sync(); - final Future result = residentRunner.attach( + final Future result = residentRunner.attach( appStartedCompleter: futureAppStart, connectionInfoCompleter: futureConnectionInfo, enableDevTools: true, @@ -393,7 +390,7 @@ void main() { expect(futureConnectionInfo.isCompleted, true); expect((await connectionInfo).baseUri, 'foo://bar'); expect(futureAppStart.isCompleted, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner can handle an RPC exception from hot reload', () => testbed.run(() async { @@ -424,7 +421,7 @@ void main() { fastReassemble: false, )), )); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), })); @@ -447,7 +444,7 @@ void main() { expect(result.fatal, false); expect(result.code, 1); expect(result.message, contains('Device initialization has not completed.')); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner can handle an reload-barred exception from hot reload', () => testbed.run(() async { @@ -480,7 +477,7 @@ void main() { fastReassemble: false, )), )); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), })); @@ -527,7 +524,7 @@ void main() { fastReassemble: false, )), )); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), })); @@ -546,7 +543,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.reassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, ), @@ -573,7 +570,7 @@ void main() { final OperationResult result = await residentRunner.restart(); expect(result.code, 0); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner reports error with missing entrypoint file', () => testbed.run(() async { @@ -587,7 +584,7 @@ void main() { 'isolates': [ fakeUnpausedIsolate.toJson(), ], - }).toJson(), + })!.toJson(), ), const FakeVmServiceRequest( method: 'reloadSources', @@ -613,7 +610,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.reassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, ), @@ -647,7 +644,7 @@ void main() { 'isolates': [ fakeUnpausedIsolate.toJson(), ], - }).toJson(), + })!.toJson(), ), const FakeVmServiceRequest( method: 'reloadSources', @@ -677,7 +674,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.reassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, ), @@ -711,7 +708,7 @@ void main() { 'isolates': [ fakeUnpausedIsolate.toJson(), ], - }).toJson(), + })!.toJson(), ), const FakeVmServiceRequest( method: 'reloadSources', @@ -737,7 +734,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.reassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, ), @@ -758,7 +755,7 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'reload'); - expect(event.parameters.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); + expect(event.parameters?.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); }, overrides: { Usage: () => TestUsage(), })); @@ -800,7 +797,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.fastReassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, 'className': 'FOO', }, @@ -811,7 +808,7 @@ void main() { BuildInfo.debug, FakeResidentCompiler(), devFS, - )..vmService = fakeVmServiceHost.vmService; + )..vmService = fakeVmServiceHost!.vmService; residentRunner = HotRunner( [ flutterDevice, @@ -844,7 +841,7 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'reload'); - expect(event.parameters.fastReassemble, true); + expect(event.parameters?.fastReassemble, true); }, overrides: { FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform(), @@ -891,7 +888,7 @@ void main() { ), FakeVmServiceRequest( method: 'ext.flutter.fastReassemble', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, 'className': 'FOO', }, @@ -902,7 +899,7 @@ void main() { BuildInfo.debug, FakeResidentCompiler(), devFS, - )..vmService = fakeVmServiceHost.vmService; + )..vmService = fakeVmServiceHost!.vmService; residentRunner = HotRunner( [ flutterDevice, @@ -949,14 +946,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakeUnpausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), listViews, const FakeVmServiceRequest( @@ -996,8 +993,8 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'restart'); - expect(event.parameters.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(event.parameters?.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), })); @@ -1009,14 +1006,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakePausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), const FakeVmServiceRequest( method: 'setIsolatePauseMode', @@ -1072,7 +1069,7 @@ void main() { final OperationResult result = await residentRunner.restart(fullRestart: true); expect(result.isOk, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner will alternative the name of the dill file uploaded for a hot restart', () => testbed.run(() async { @@ -1082,14 +1079,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakeUnpausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), listViews, const FakeVmServiceRequest( @@ -1116,14 +1113,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakeUnpausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), listViews, const FakeVmServiceRequest( @@ -1150,14 +1147,14 @@ void main() { listViews, FakeVmServiceRequest( method: 'getIsolate', - args: { + args: { 'isolateId': fakeUnpausedIsolate.id, }, jsonResponse: fakeUnpausedIsolate.toJson(), ), FakeVmServiceRequest( method: 'getVM', - jsonResponse: vm_service.VM.parse({}).toJson(), + jsonResponse: vm_service.VM.parse({})!.toJson(), ), listViews, const FakeVmServiceRequest( @@ -1194,7 +1191,7 @@ void main() { await residentRunner.restart(fullRestart: true); await residentRunner.restart(fullRestart: true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner Can handle an RPC exception from hot restart', () => testbed.run(() async { @@ -1225,7 +1222,7 @@ void main() { fastReassemble: false, )), )); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), })); @@ -1391,6 +1388,47 @@ flutter: expect(testLogger.statusText, isEmpty); })); + testUsingContext('ResidentRunner generates files when l10n.yaml exists', () => testbed.run(() async { + globals.fs.file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + final File arbFile = globals.fs.file(globals.fs.path.join('lib', 'l10n', 'app_en.arb')) + ..createSync(recursive: true); + arbFile.writeAsStringSync(''' +{ + "helloWorld": "Hello, World!", + "@helloWorld": { + "description": "Sample description" + } +}'''); + globals.fs.file('l10n.yaml').createSync(); + globals.fs.file('pubspec.yaml').writeAsStringSync('flutter:\n generate: true\n'); + + fakeVmServiceHost = FakeVmServiceHost(requests: []); + final FakeResidentCompiler residentCompiler = FakeResidentCompiler() + ..nextOutput = const CompilerOutput('foo', 1 ,[]); + residentRunner = HotRunner( + [ + flutterDevice, + ], + stayResident: false, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + ); + flutterDevice.generator = residentCompiler; + + await residentRunner.run(); + + final File generatedLocalizationsFile = globals.fs.directory('.dart_tool') + .childDirectory('flutter_gen') + .childDirectory('gen_l10n') + .childFile('app_localizations.dart'); + expect(generatedLocalizationsFile.existsSync(), isTrue); + + // Completing this future ensures that the daemon can exit correctly. + expect(await residentRunner.waitForAppToFinish(), 1); + })); + testUsingContext('ResidentRunner printHelpDetails hot runner', () => testbed.run(() { fakeVmServiceHost = FakeVmServiceHost(requests: []); @@ -1554,7 +1592,7 @@ flutter: await residentRunner.writeSkSL(); expect(testLogger.statusText, contains('No data was received')); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('ResidentRunner can write SkSL data to a unique file with engine revision, platform, and device name', () => testbed.run(() async { @@ -1582,7 +1620,7 @@ flutter: 'engineRevision': 'abcdefg', 'data': {'A': 'B'}, }); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { FileSystemUtils: () => FileSystemUtils( fileSystem: globals.fs, @@ -1606,7 +1644,7 @@ flutter: devtoolsHandler: createNoOpHandler, ); - final Future result = residentRunner.attach(); + final Future result = residentRunner.attach(); expect(await result, 0); })); @@ -1625,13 +1663,13 @@ flutter: final TestFlutterDevice flutterDevice = TestFlutterDevice( device, ); - flutterDevice.vmService = fakeVmServiceHost.vmService; + flutterDevice.vmService = fakeVmServiceHost!.vmService; final Future exitFuture = flutterDevice.exitApps(); await expectLater(exitFuture, completes); expect(device.appStopped, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('HotRunner writes vm service file when providing debugging option', () => testbed.run(() async { @@ -1652,7 +1690,7 @@ flutter: await residentRunner.run(enableDevTools: true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); expect(await globals.fs.file('foo').readAsString(), testUri.toString()); })); @@ -1856,7 +1894,7 @@ flutter: await residentRunner.run(enableDevTools: true); expect(testLogger.errorText, contains('Failed to write vmservice-out-file at foo')); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); }, overrides: { FileSystem: () => ThrowingForwardingFileSystem(MemoryFileSystem.test()), })); @@ -1879,13 +1917,13 @@ flutter: await residentRunner.run(enableDevTools: true); expect(await globals.fs.file('foo').readAsString(), testUri.toString()); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(fakeVmServiceHost?.hasRemainingExpectations, false); })); testUsingContext('FlutterDevice uses dartdevc configuration when targeting web', () async { fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.web_javascript); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -1895,16 +1933,16 @@ flutter: ), target: null, platform: FakePlatform(), - )).generator as DefaultResidentCompiler; + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.initializeFromDill, + expect(residentCompiler!.initializeFromDill, globals.fs.path.join(getBuildDirectory(), 'fbbe6a61fb7a1de317d381f8df4814e5.cache.dill')); expect(residentCompiler.librariesSpec, - globals.fs.file(globals.artifacts.getHostArtifact(HostArtifact.flutterWebLibrariesJson)) + globals.fs.file(globals.artifacts!.getHostArtifact(HostArtifact.flutterWebLibrariesJson)) .uri.toString()); expect(residentCompiler.targetModel, TargetModel.dartdevc); expect(residentCompiler.sdkRoot, - '${globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk).path}/'); + '${globals.artifacts!.getHostArtifact(HostArtifact.flutterWebSdk).path}/'); expect(residentCompiler.platformDill, 'file:///HostArtifact.webPlatformKernelDill'); }, overrides: { Artifacts: () => Artifacts.test(), @@ -1916,7 +1954,7 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.web_javascript); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -1926,16 +1964,16 @@ flutter: ), target: null, platform: FakePlatform(), - )).generator as DefaultResidentCompiler; + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.initializeFromDill, + expect(residentCompiler!.initializeFromDill, globals.fs.path.join(getBuildDirectory(), '80b1a4cf4e7b90e1ab5f72022a0bc624.cache.dill')); expect(residentCompiler.librariesSpec, - globals.fs.file(globals.artifacts.getHostArtifact(HostArtifact.flutterWebLibrariesJson)) + globals.fs.file(globals.artifacts!.getHostArtifact(HostArtifact.flutterWebLibrariesJson)) .uri.toString()); expect(residentCompiler.targetModel, TargetModel.dartdevc); expect(residentCompiler.sdkRoot, - '${globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk).path}/'); + '${globals.artifacts!.getHostArtifact(HostArtifact.flutterWebSdk).path}/'); expect(residentCompiler.platformDill, 'file:///HostArtifact.webPlatformSoundKernelDill'); }, overrides: { Artifacts: () => Artifacts.test(), @@ -1947,7 +1985,7 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -1955,10 +1993,10 @@ flutter: treeShakeIcons: false, extraFrontEndOptions: [], ), - target: null, platform: null, - )).generator as DefaultResidentCompiler; + target: null, platform: FakePlatform(), + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.extraFrontEndOptions, + expect(residentCompiler!.extraFrontEndOptions, contains('--flutter-widget-cache')); }, overrides: { Artifacts: () => Artifacts.test(), @@ -1972,7 +2010,7 @@ flutter: final FakeDevice device = FakeDevice(); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -1980,10 +2018,10 @@ flutter: treeShakeIcons: false, extraFrontEndOptions: [], ), - target: null, platform: null, - )).generator as DefaultResidentCompiler; + target: null, platform: FakePlatform(), + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.extraFrontEndOptions, + expect(residentCompiler!.extraFrontEndOptions, contains('--enable-experiment=alternative-invalidation-strategy')); }, overrides: { Artifacts: () => Artifacts.test(), @@ -1995,7 +2033,7 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -2004,10 +2042,10 @@ flutter: extraFrontEndOptions: [], initializeFromDill: '/foo/bar.dill', ), - target: null, platform: null, - )).generator as DefaultResidentCompiler; + target: null, platform: FakePlatform(), + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.initializeFromDill, '/foo/bar.dill'); + expect(residentCompiler!.initializeFromDill, '/foo/bar.dill'); expect(residentCompiler.assumeInitializeFromDillUpToDate, false); }, overrides: { Artifacts: () => Artifacts.test(), @@ -2019,7 +2057,7 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(); - final DefaultResidentCompiler residentCompiler = (await FlutterDevice.create( + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( device, buildInfo: const BuildInfo( BuildMode.debug, @@ -2028,10 +2066,10 @@ flutter: extraFrontEndOptions: [], assumeInitializeFromDillUpToDate: true, ), - target: null, platform: null, - )).generator as DefaultResidentCompiler; + target: null, platform: FakePlatform(), + )).generator as DefaultResidentCompiler?; - expect(residentCompiler.assumeInitializeFromDillUpToDate, true); + expect(residentCompiler!.assumeInitializeFromDillUpToDate, true); }, overrides: { Artifacts: () => Artifacts.test(), FileSystem: () => MemoryFileSystem.test(), @@ -2042,7 +2080,7 @@ flutter: fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags, dds.UriConverter uriConverter}) { + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes = true, bool ipv6 = false, Uri? serviceUri, List cachedUserTags = const [], dds.UriConverter? uriConverter}) { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isTrue); expect(ipv6, isFalse); @@ -2062,7 +2100,7 @@ flutter: runZonedGuarded(() { flutterDevice.connect(allowExistingDdsInstance: true).then((_) => done.complete()); }, (Object e, StackTrace st) { - expect(e is ToolExit, true); + expect(e, isA()); expect((e as ToolExit).message, contains('Existing VM service clients prevent DDS from taking control.', )); @@ -2075,14 +2113,14 @@ flutter: } }, overrides: { VMServiceConnector: () => (Uri httpUri, { - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - io.CompressionOptions compression, - Device device, - Logger logger, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + io.CompressionOptions? compression, + Device? device, + required Logger logger, }) async => FakeVmServiceHost(requests: []).vmService, })); @@ -2091,7 +2129,7 @@ flutter: final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); final Completerdone = Completer(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags, dds.UriConverter uriConverter}) async { + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes = true, bool ipv6 = false, Uri? serviceUri, List cachedUserTags = const [], dds.UriConverter? uriConverter}) async { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isFalse); expect(ipv6, isTrue); @@ -2099,7 +2137,7 @@ flutter: expect(cachedUserTags, isEmpty); expect(uriConverter, isNull); done.complete(); - return null; + return FakeDartDevelopmentService(); }; final TestFlutterDevice flutterDevice = TestFlutterDevice( device, @@ -2109,14 +2147,14 @@ flutter: await done.future; }, overrides: { VMServiceConnector: () => (Uri httpUri, { - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - io.CompressionOptions compression, - Device device, - Logger logger, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + io.CompressionOptions? compression, + Device? device, + required Logger logger, }) async => FakeVmServiceHost(requests: []).vmService, })); @@ -2125,7 +2163,14 @@ flutter: final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); final Completerdone = Completer(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags, dds.UriConverter uriConverter}) async { + ddsLauncherCallback = ( + Uri uri, { + bool enableAuthCodes = false, + bool ipv6 = false, + Uri? serviceUri, + List cachedUserTags = const [], + dds.UriConverter? uriConverter, + }) async { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isFalse); expect(ipv6, isTrue); @@ -2133,7 +2178,7 @@ flutter: expect(cachedUserTags, isEmpty); expect(uriConverter, isNotNull); done.complete(); - return null; + return FakeDartDevelopmentService(); }; final TestFlutterDevice flutterDevice = TestFlutterDevice( device, @@ -2143,14 +2188,14 @@ flutter: await done.future; }, overrides: { VMServiceConnector: () => (Uri httpUri, { - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - io.CompressionOptions compression, - Device device, - Logger logger, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + io.CompressionOptions compression = io.CompressionOptions.compressionDefault, + Device? device, + required Logger logger, }) async => FakeVmServiceHost(requests: []).vmService, dds.UriConverter: () => (String uri) => 'test', })); @@ -2159,7 +2204,14 @@ flutter: // See https://github.com/flutter/flutter/issues/72385 for context. final FakeDevice device = FakeDevice() ..dds = DartDevelopmentService(); - ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri, List cachedUserTags, dds.UriConverter uriConverter}) { + ddsLauncherCallback = ( + Uri uri, { + bool enableAuthCodes = false, + bool ipv6 = false, + Uri? serviceUri, + List cachedUserTags = const [], + dds.UriConverter? uriConverter, + }) { expect(uri, Uri(scheme: 'foo', host: 'bar')); expect(enableAuthCodes, isTrue); expect(ipv6, isFalse); @@ -2177,7 +2229,7 @@ flutter: runZonedGuarded(() { flutterDevice.connect(allowExistingDdsInstance: true).then((_) => done.complete()); }, (Object e, StackTrace st) { - expect(e is StateError, true); + expect(e, isA()); expect((e as StateError).message, contains('No URI')); expect(testLogger.errorText, contains( 'DDS has failed to start and there is not an existing DDS instance', @@ -2191,14 +2243,14 @@ flutter: } }, overrides: { VMServiceConnector: () => (Uri httpUri, { - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - io.CompressionOptions compression, - Device device, - Logger logger, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + io.CompressionOptions compression = io.CompressionOptions.compressionDefault, + Device? device, + required Logger logger, }) async => FakeVmServiceHost(requests: []).vmService, })); @@ -2222,7 +2274,7 @@ flutter: ); await residentRunner.cleanupAtFinish(); - expect((residentRunner.residentDevtoolsHandler as NoOpDevtoolsHandler).wasShutdown, true); + expect((residentRunner.residentDevtoolsHandler! as NoOpDevtoolsHandler).wasShutdown, true); })); testUsingContext('HotRunner sets asset directory when first evict assets', () => testbed.run(() async { @@ -2241,12 +2293,12 @@ flutter: devtoolsHandler: createNoOpHandler, ); - (flutterDevice.devFS as FakeDevFS).assetPathsToEvict = {'asset'}; + (flutterDevice.devFS! as FakeDevFS).assetPathsToEvict = {'asset'}; - expect(flutterDevice.devFS.hasSetAssetDirectory, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, isFalse); await (residentRunner as HotRunner).evictDirtyAssets(); - expect(flutterDevice.devFS.hasSetAssetDirectory, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, isTrue); + expect(fakeVmServiceHost!.hasRemainingExpectations, isFalse); })); testUsingContext('HotRunner sets asset directory when first evict shaders', () => testbed.run(() async { @@ -2265,12 +2317,12 @@ flutter: devtoolsHandler: createNoOpHandler, ); - (flutterDevice.devFS as FakeDevFS).shaderPathsToEvict = {'foo.frag'}; + (flutterDevice.devFS! as FakeDevFS).shaderPathsToEvict = {'foo.frag'}; - expect(flutterDevice.devFS.hasSetAssetDirectory, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, false); await (residentRunner as HotRunner).evictDirtyAssets(); - expect(flutterDevice.devFS.hasSetAssetDirectory, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, true); + expect(fakeVmServiceHost!.hasRemainingExpectations, false); })); testUsingContext('HotRunner does not sets asset directory when no assets to evict', () => testbed.run(() async { @@ -2286,10 +2338,10 @@ flutter: devtoolsHandler: createNoOpHandler, ); - expect(flutterDevice.devFS.hasSetAssetDirectory, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, false); await (residentRunner as HotRunner).evictDirtyAssets(); - expect(flutterDevice.devFS.hasSetAssetDirectory, false); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, false); + expect(fakeVmServiceHost!.hasRemainingExpectations, false); })); testUsingContext('HotRunner does not set asset directory if it has been set before', () => testbed.run(() async { @@ -2307,15 +2359,25 @@ flutter: devtoolsHandler: createNoOpHandler, ); - (flutterDevice.devFS as FakeDevFS).assetPathsToEvict = {'asset'}; - flutterDevice.devFS.hasSetAssetDirectory = true; + (flutterDevice.devFS! as FakeDevFS).assetPathsToEvict = {'asset'}; + flutterDevice.devFS!.hasSetAssetDirectory = true; await (residentRunner as HotRunner).evictDirtyAssets(); - expect(flutterDevice.devFS.hasSetAssetDirectory, true); - expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect(flutterDevice.devFS!.hasSetAssetDirectory, true); + expect(fakeVmServiceHost!.hasRemainingExpectations, false); })); } +// NOTE: implements [dds.DartDevelopmentService] and NOT [DartDevelopmentService] +// from package:flutter_tools. +class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService { + @override + Future get done => Future.value(); + + @override + Uri? get uri => null; +} + class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException { FakeDartDevelopmentServiceException({this.message = defaultMessage}); @@ -2328,18 +2390,17 @@ class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceE } class TestFlutterDevice extends FlutterDevice { - TestFlutterDevice(Device device, { Stream observatoryUris }) - : super(device, buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler()) { - _observatoryUris = observatoryUris; - } + TestFlutterDevice(super.device, { Stream? observatoryUris }) + : _observatoryUris = observatoryUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler()); + + final Stream? _observatoryUris; @override - Stream get observatoryUris => _observatoryUris; - Stream _observatoryUris; + Stream get observatoryUris => _observatoryUris!; } class ThrowingForwardingFileSystem extends ForwardingFileSystem { - ThrowingForwardingFileSystem(FileSystem delegate) : super(delegate); + ThrowingForwardingFileSystem(super.delegate); @override File file(dynamic path) { @@ -2351,19 +2412,19 @@ class ThrowingForwardingFileSystem extends ForwardingFileSystem { } class FakeFlutterDevice extends Fake implements FlutterDevice { - FakeVmServiceHost Function() vmServiceHost; - Uri testUri; + FakeVmServiceHost? Function()? vmServiceHost; + Uri? testUri; UpdateFSReport report = UpdateFSReport( success: true, invalidatedSourcesCount: 1, ); - Exception reportError; - Exception runColdError; + Exception? reportError; + Exception? runColdError; int runHotCode = 0; int runColdCode = 0; @override - ResidentCompiler generator; + ResidentCompiler? generator; @override DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler(); @@ -2372,21 +2433,21 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { TargetPlatform get targetPlatform => TargetPlatform.android; @override - Stream get observatoryUris => Stream.value(testUri); + Stream get observatoryUris => Stream.value(testUri); @override - FlutterVmService get vmService => vmServiceHost?.call()?.vmService; + FlutterVmService? get vmService => vmServiceHost?.call()?.vmService; - DevFS _devFS; + DevFS? _devFS; @override - DevFS get devFS => _devFS; + DevFS? get devFS => _devFS; @override - set devFS(DevFS value) { } + set devFS(DevFS? value) { } @override - Device device; + Device? device; @override Future stopEchoingDeviceLog() async { } @@ -2396,55 +2457,55 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { @override Future setupDevFS(String fsName, Directory rootDirectory) async { - return testUri; + return testUri!; } @override - Future runHot({HotRunner hotRunner, String route}) async { + Future runHot({required HotRunner hotRunner, String? route}) async { return runHotCode; } @override - Future runCold({ColdRunner coldRunner, String route}) async { + Future runCold({required ColdRunner coldRunner, String? route}) async { if (runColdError != null) { - throw runColdError; + throw runColdError!; } return runColdCode; } @override Future connect({ - ReloadSources reloadSources, - Restart restart, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, - int hostVmServicePort, - int ddsPort, + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + int? hostVmServicePort, + int? ddsPort, bool disableServiceAuthCodes = false, bool enableDds = true, bool cacheStartupProfile = false, - @required bool allowExistingDdsInstance, + required bool allowExistingDdsInstance, bool ipv6 = false, }) async { } @override Future updateDevFS({ - Uri mainUri, - String target, - AssetBundle bundle, - DateTime firstBuildTime, + required Uri mainUri, + String? target, + AssetBundle? bundle, + DateTime? firstBuildTime, bool bundleFirstUpload = false, bool bundleDirty = false, bool fullRestart = false, - String projectRootPath, - String pathToReload, - String dillOutputPath, - List invalidatedFiles, - PackageConfig packageConfig, + String? projectRootPath, + required String pathToReload, + required String dillOutputPath, + required List invalidatedFiles, + required PackageConfig packageConfig, }) async { if (reportError != null) { - throw reportError; + throw reportError!; } return report; } @@ -2455,25 +2516,25 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { class FakeDelegateFlutterDevice extends FlutterDevice { FakeDelegateFlutterDevice( - Device device, + super.device, BuildInfo buildInfo, ResidentCompiler residentCompiler, this.fakeDevFS, - ) : super(device, buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler()); + ) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler()); @override Future connect({ - ReloadSources reloadSources, - Restart restart, + ReloadSources? reloadSources, + Restart? restart, bool enableDds = true, bool cacheStartupProfile = false, bool disableServiceAuthCodes = false, bool ipv6 = false, - CompileExpression compileExpression, - GetSkSLMethod getSkSLMethod, - int hostVmServicePort, - int ddsPort, - PrintStructuredErrorLogMethod printStructuredErrorLogMethod, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + int? hostVmServicePort, + int? ddsPort, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, bool allowExistingDdsInstance = false, }) async { } @@ -2481,27 +2542,27 @@ class FakeDelegateFlutterDevice extends FlutterDevice { final DevFS fakeDevFS; @override - DevFS get devFS => fakeDevFS; + DevFS? get devFS => fakeDevFS; @override - set devFS(DevFS value) {} + set devFS(DevFS? value) {} } class FakeResidentCompiler extends Fake implements ResidentCompiler { - CompilerOutput nextOutput; + CompilerOutput? nextOutput; bool didSuppressErrors = false; @override - Future recompile( + Future recompile( Uri mainUri, - List invalidatedFiles, { - @required String outputPath, - @required PackageConfig packageConfig, - @required String projectRootPath, - @required FileSystem fs, + List? invalidatedFiles, { + required String outputPath, + required PackageConfig packageConfig, + String? projectRootPath, + required FileSystem fs, bool suppressErrors = false, bool checkDartPluginRegistry = false, - File dartPluginRegistrant, + File? dartPluginRegistrant, }) async { didSuppressErrors = suppressErrors; return nextOutput ?? const CompilerOutput('foo.dill', 0, []); @@ -2517,14 +2578,14 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator { @override Future findInvalidated({ - @required DateTime lastCompiled, - @required List urisToMonitor, - @required String packagesPath, - @required PackageConfig packageConfig, + required DateTime? lastCompiled, + required List urisToMonitor, + required String packagesPath, + required PackageConfig packageConfig, bool asyncScanning = false, }) async { return InvalidationResult( - packageConfig: packageConfig ?? PackageConfig.empty, + packageConfig: packageConfig, uris: [Uri.parse('file:///hello_world/main.dart'), ]); } @@ -2580,7 +2641,7 @@ class FakeDevice extends Fake implements Device { String get name => 'FakeDevice'; @override - DartDevelopmentService dds; + late DartDevelopmentService dds; @override Future dispose() async { @@ -2588,7 +2649,7 @@ class FakeDevice extends Fake implements Device { } @override - Future stopApp(covariant ApplicationPackage app, {String userIdentifier}) async { + Future stopApp(covariant ApplicationPackage? app, {String? userIdentifier}) async { appStopped = true; return true; } @@ -2603,7 +2664,7 @@ class FakeDevice extends Fake implements Device { @override FutureOr getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) => NoOpDeviceLogReader(name); @@ -2613,10 +2674,10 @@ class FakeDevice extends Fake implements Device { class FakeDevFS extends Fake implements DevFS { @override - DateTime lastCompiled = DateTime(2000); + DateTime? lastCompiled = DateTime(2000); @override - PackageConfig lastPackageConfig = PackageConfig.empty; + PackageConfig? lastPackageConfig = PackageConfig.empty; @override List sources = []; @@ -2653,22 +2714,22 @@ class FakeDevFS extends Fake implements DevFS { @override Future update({ - @required Uri mainUri, - @required ResidentCompiler generator, - @required bool trackWidgetCreation, - @required String pathToReload, - @required List invalidatedFiles, - @required PackageConfig packageConfig, - @required String dillOutputPath, - @required DevelopmentShaderCompiler shaderCompiler, - DevFSWriter devFSWriter, - String target, - AssetBundle bundle, - DateTime firstBuildTime, + required Uri mainUri, + required ResidentCompiler generator, + required bool trackWidgetCreation, + required String pathToReload, + required List invalidatedFiles, + required PackageConfig packageConfig, + required String dillOutputPath, + required DevelopmentShaderCompiler shaderCompiler, + DevFSWriter? devFSWriter, + String? target, + AssetBundle? bundle, + DateTime? firstBuildTime, bool bundleFirstUpload = false, bool fullRestart = false, - String projectRootPath, - File dartPluginRegistrant, + String? projectRootPath, + File? dartPluginRegistrant, }) async { return nextUpdateReport; } @@ -2678,7 +2739,7 @@ class FakeShaderCompiler implements DevelopmentShaderCompiler { const FakeShaderCompiler(); @override - void configureCompiler(TargetPlatform platform, { @required bool enableImpeller }) { } + void configureCompiler(TargetPlatform? platform, { required bool enableImpeller }) { } @override Future recompileShader(DevFSContent inputShader) { diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 6845de238dcef..8a492d3d480b3 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -1049,6 +1049,69 @@ void main() { ProcessManager: () => processManager, }); + testUsingContext('ResidentWebRunner generates files when l10n.yaml exists', () async { + fakeVmServiceHost = + FakeVmServiceHost(requests: kAttachExpectations.toList()); + setupMocks(); + final ResidentRunner residentWebRunner = ResidentWebRunner( + flutterDevice, + flutterProject: + FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + ipv6: true, + stayResident: false, + fileSystem: fileSystem, + logger: BufferLogger.test(), + usage: globals.flutterUsage, + systemClock: globals.systemClock, + ); + + // Create necessary files. + globals.fs.file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + globals.fs.file(globals.fs.path.join('lib', 'l10n', 'app_en.arb')) + ..createSync(recursive: true) + ..writeAsStringSync(''' +{ + "helloWorld": "Hello, World!", + "@helloWorld": { + "description": "Sample description" + } +}'''); + globals.fs.file('l10n.yaml').createSync(); + globals.fs.file('pubspec.yaml').writeAsStringSync(''' +flutter: + generate: true +'''); + globals.fs.directory('.dart_tool') + .childFile('package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync(''' +{ + "configVersion": 2, + "packages": [ + { + "name": "path_provider_linux", + "rootUri": "../../../path_provider_linux", + "packageUri": "lib/", + "languageVersion": "2.12" + } + ] +} +'''); + expect(await residentWebRunner.run(), 0); + final File generatedLocalizationsFile = globals.fs.directory('.dart_tool') + .childDirectory('flutter_gen') + .childDirectory('gen_l10n') + .childFile('app_localizations.dart'); + expect(generatedLocalizationsFile.existsSync(), isTrue); + // Completing this future ensures that the daemon can exit correctly. + expect(fakeVmServiceHost.hasRemainingExpectations, false); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); + // While this file should be ignored on web, generating it here will cause a // perf regression in hot restart. testUsingContext('Does not generate dart_plugin_registrant.dart', () async { @@ -1385,7 +1448,7 @@ class FakeChromeTab extends Fake implements ChromeTab { final FakeWipConnection connection = FakeWipConnection(); @override - Future connect() async { + Future connect({Function/*?*/ onError}) async { return connection; } } diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index a995720179a6c..4c59a501039bc 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/net.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/globals.dart' as globals; @@ -34,7 +35,7 @@ void main() { // Instead of exiting with dart:io exit(), this causes an exception to // be thrown, which we catch with the onError callback in the zone below. // - // Tests might trigger exit() multiple times. In real life, exit() would + // Tests might trigger exit() multiple times. In real life, exit() would // cause the VM to terminate immediately, so only the first one matters. firstExitCode = null; io.setExitFunctionForTests((int exitCode) { @@ -68,6 +69,7 @@ void main() { // This flutterVersion disables crash reporting. flutterVersion: '[user-branch]/', reportCrashes: true, + shutdownHooks: ShutdownHooks(), )); return null; }, @@ -102,7 +104,7 @@ void main() { // This Completer completes when CrashingFlutterCommand.runCommand // completes, but ideally we'd want it to complete when execution resumes - // runner.run. Currently the distinction does not matter, but if it ever + // runner.run. Currently the distinction does not matter, but if it ever // does, this test might fail to catch a regression of // https://github.com/flutter/flutter/issues/56406. final Completer commandCompleter = Completer(); @@ -120,6 +122,7 @@ void main() { // This flutterVersion disables crash reporting. flutterVersion: '[user-branch]/', reportCrashes: true, + shutdownHooks: ShutdownHooks(), )); return null; }, @@ -159,16 +162,17 @@ void main() { // catch it in a zone. unawaited(runZoned>( () { - unawaited(runner.run( - ['crash'], - () => [ - CrashingFlutterCommand(), - ], - // This flutterVersion disables crash reporting. - flutterVersion: '[user-branch]/', - reportCrashes: true, - )); - return null; + unawaited(runner.run( + ['crash'], + () => [ + CrashingFlutterCommand(), + ], + // This flutterVersion disables crash reporting. + flutterVersion: '[user-branch]/', + reportCrashes: true, + shutdownHooks: ShutdownHooks(), + )); + return null; }, onError: (Object error, StackTrace stack) { // ignore: deprecated_member_use expect(firstExitCode, isNotNull); @@ -338,7 +342,7 @@ class CustomBugInstructions extends UserMessages { /// A fake [CrashReporter] that waits for a [Future] to complete. /// /// Used to exacerbate a race between the success and failure paths of -/// [runner.run]. See https://github.com/flutter/flutter/issues/56406. +/// [runner.run]. See https://github.com/flutter/flutter/issues/56406. class WaitingCrashReporter implements CrashReporter { WaitingCrashReporter(Future future) : _future = future; diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index df8053a82c49f..861d90a8ef4ad 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -440,9 +440,9 @@ void main() { GitTagVersion gitTagVersion; // Master channel - gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash'); - expect(gitTagVersion.frameworkVersionFor(hash), '1.3.0-0.0.pre.13'); - expect(gitTagVersion.gitTag, '1.2.3-4.5.pre'); + gitTagVersion = GitTagVersion.parse('1.2.0-4.5.pre-13-g$hash'); + expect(gitTagVersion.frameworkVersionFor(hash), '1.2.0-5.0.pre.13'); + expect(gitTagVersion.gitTag, '1.2.0-4.5.pre'); expect(gitTagVersion.devVersion, 4); expect(gitTagVersion.devPatch, 5); @@ -543,7 +543,7 @@ void main() { }); testUsingContext('determine reports correct git describe version if HEAD is not at a tag', () { - const String devTag = '1.2.3-2.0.pre'; + const String devTag = '1.2.0-2.0.pre'; const String headRevision = 'abcd1234'; const String commitsAhead = '12'; final FakeProcessManager fakeProcessManager = FakeProcessManager.list( @@ -565,8 +565,8 @@ void main() { final FakePlatform platform = FakePlatform(); final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, platform, workingDirectory: '.'); - // reported version should increment the y - expect(gitTagVersion.frameworkVersionFor(headRevision), '1.3.0-0.0.pre.12'); + // reported version should increment the m + expect(gitTagVersion.frameworkVersionFor(headRevision), '1.2.0-3.0.pre.12'); }); testUsingContext('determine does not call fetch --tags', () { diff --git a/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart b/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart index b5913c8723535..32ad2c2daab7d 100644 --- a/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart +++ b/packages/flutter_tools/test/general.shard/web/golden_comparator_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; @@ -28,7 +26,7 @@ final Uint8List imageBytes = Uint8List.fromList([1, 2, 3, 4, 5]); void main() { group('Test that TestGoldenComparator', () { - FakeProcessManager processManager; + late FakeProcessManager processManager; setUp(() { processManager = FakeProcessManager.empty(); @@ -63,7 +61,7 @@ void main() { webRenderer: WebRendererMode.html, ); - final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); + final String? result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, null); }); @@ -92,7 +90,7 @@ void main() { webRenderer: WebRendererMode.canvaskit, ); - final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); + final String? result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, 'some message'); }); @@ -125,10 +123,10 @@ void main() { webRenderer: WebRendererMode.html, ); - final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); + final String? result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result1, 'some message'); - final String result2 = await comparator.compareGoldens(testUri, imageBytes, goldenKey2, false); + final String? result2 = await comparator.compareGoldens(testUri, imageBytes, goldenKey2, false); expect(result2, 'some other message'); }); @@ -170,10 +168,10 @@ void main() { webRenderer: WebRendererMode.canvaskit, ); - final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); + final String? result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result1, 'some message'); - final String result2 = await comparator.compareGoldens(testUri2, imageBytes, goldenKey2, false); + final String? result2 = await comparator.compareGoldens(testUri2, imageBytes, goldenKey2, false); expect(result2, 'some other message'); }); @@ -205,7 +203,7 @@ void main() { webRenderer: WebRendererMode.html, ); - final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); + final String? result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false); expect(result, null); await comparator.close(); diff --git a/packages/flutter_tools/test/general.shard/windows_version_validator_test.dart b/packages/flutter_tools/test/general.shard/windows_version_validator_test.dart new file mode 100644 index 0000000000000..da849cab90f77 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/windows_version_validator_test.dart @@ -0,0 +1,209 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/doctor_validator.dart'; +import 'package:flutter_tools/src/windows/windows_version_validator.dart'; + +import '../src/common.dart'; +import '../src/fake_process_manager.dart'; + +/// Example output from `systeminfo` from a Windows 10 host +const String validWindows10StdOut = r''' +Host Name: XXXXXXXXXXXX +OS Name: Microsoft Windows 10 Enterprise +OS Version: 10.0.19044 N/A Build 19044 +OS Manufacturer: Microsoft Corporation +OS Configuration: Member Workstation +OS Build Type: Multiprocessor Free +Registered Owner: N/A +Registered Organization: N/A +Product ID: XXXXXXXXXXXX +Original Install Date: 8/4/2022, 2:51:28 PM +System Boot Time: 8/10/2022, 1:03:10 PM +System Manufacturer: Google +System Model: Google Compute Engine +System Type: x64-based PC +Processor(s): 1 Processor(s) Installed. + [01]: AMD64 Family 23 Model 49 Stepping 0 AuthenticAMD ~2250 Mhz +BIOS Version: Google Google, 6/29/2022 +Windows Directory: C:\\Windows +System Directory: C:\\Windows\\system32 +Boot Device: \\Device\\HarddiskVolume2 +System Locale: en-us;English (United States) +Input Locale: en-us;English (United States) +Time Zone: (UTC-08:00) Pacific Time (US & Canada) +Total Physical Memory: 32,764 MB +Available Physical Memory: 17,852 MB +Virtual Memory: Max Size: 33,788 MB +Virtual Memory: Available: 18,063 MB +Virtual Memory: In Use: 15,725 MB +Page File Location(s): C:\\pagefile.sys +Domain: ad.corp.google.com +Logon Server: \\CBF-DC-8 +Hotfix(s): 7 Hotfix(s) Installed. + [01]: KB5013624 + [02]: KB5003791 + [03]: KB5012170 + [04]: KB5016616 + [05]: KB5014032 + [06]: KB5014671 + [07]: KB5015895 +Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed. +'''; + +/// Example output from `systeminfo` from version != 10 +const String invalidWindowsStdOut = r''' +Host Name: XXXXXXXXXXXX +OS Name: Microsoft Windows 8.1 Enterprise +OS Version: 6.3.9600 Build 9600 +OS Manufacturer: Microsoft Corporation +OS Configuration: Member Workstation +OS Build Type: Multiprocessor Free +Registered Owner: N/A +Registered Organization: N/A +Product ID: XXXXXXXXXXXX +Original Install Date: 8/4/2022, 2:51:28 PM +System Boot Time: 8/10/2022, 1:03:10 PM +System Manufacturer: Google +System Model: Google Compute Engine +System Type: x64-based PC +Processor(s): 1 Processor(s) Installed. + [01]: AMD64 Family 23 Model 49 Stepping 0 AuthenticAMD ~2250 Mhz +BIOS Version: Google Google, 6/29/2022 +Windows Directory: C:\\Windows +System Directory: C:\\Windows\\system32 +Boot Device: \\Device\\HarddiskVolume2 +System Locale: en-us;English (United States) +Input Locale: en-us;English (United States) +Time Zone: (UTC-08:00) Pacific Time (US & Canada) +Total Physical Memory: 32,764 MB +Available Physical Memory: 17,852 MB +Virtual Memory: Max Size: 33,788 MB +Virtual Memory: Available: 18,063 MB +Virtual Memory: In Use: 15,725 MB +Page File Location(s): C:\\pagefile.sys +Domain: ad.corp.google.com +Logon Server: \\CBF-DC-8 +Hotfix(s): 7 Hotfix(s) Installed. + [01]: KB5013624 + [02]: KB5003791 + [03]: KB5012170 + [04]: KB5016616 + [05]: KB5014032 + [06]: KB5014671 + [07]: KB5015895 +Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed. +'''; + +/// The expected validation result object for +/// a passing windows version test +const ValidationResult validWindows10ValidationResult = ValidationResult( + ValidationType.installed, + [], + statusInfo: 'Installed version of Windows is version 10 or higher', +); + +/// The expected validation result object for +/// a failing exit code (!= 0) +const ValidationResult failedValidationResult = ValidationResult( + ValidationType.missing, + [], + statusInfo: 'Exit status from running `systeminfo` was unsuccessful', +); + +/// The expected validation result object for +/// a passing windows version test +const ValidationResult invalidWindowsValidationResult = ValidationResult( + ValidationType.missing, + [], + statusInfo: 'Unable to confirm if installed Windows version is 10 or greater', +); + +void main() { + testWithoutContext('Successfully running windows version check on windows 10', + () async { + final WindowsVersionValidator windowsVersionValidator = + WindowsVersionValidator( + processManager: FakeProcessManager.list( + [ + const FakeCommand( + command: ['systeminfo'], + stdout: validWindows10StdOut, + ), + ], + ), + ); + + final ValidationResult result = await windowsVersionValidator.validate(); + + expect(result.type, validWindows10ValidationResult.type, + reason: 'The ValidationResult type should be the same (installed)'); + expect(result.statusInfo, validWindows10ValidationResult.statusInfo, + reason: 'The ValidationResult statusInfo messages should be the same'); + }); + + testWithoutContext('Failing to invoke the `systeminfo` command', () async { + final WindowsVersionValidator windowsVersionValidator = + WindowsVersionValidator( + processManager: FakeProcessManager.list( + [ + const FakeCommand( + command: ['systeminfo'], + stdout: validWindows10StdOut, + exitCode: 1, + ), + ], + ), + ); + + final ValidationResult result = await windowsVersionValidator.validate(); + + expect(result.type, failedValidationResult.type, + reason: 'The ValidationResult type should be the same (missing)'); + expect(result.statusInfo, failedValidationResult.statusInfo, + reason: 'The ValidationResult statusInfo messages should be the same'); + }); + + testWithoutContext('Identifying a windows version before 10', () async { + final WindowsVersionValidator windowsVersionValidator = + WindowsVersionValidator( + processManager: FakeProcessManager.list( + [ + const FakeCommand( + command: ['systeminfo'], + stdout: invalidWindowsStdOut, + ), + ], + ), + ); + + final ValidationResult result = await windowsVersionValidator.validate(); + + expect(result.type, invalidWindowsValidationResult.type, + reason: 'The ValidationResult type should be the same (missing)'); + expect(result.statusInfo, invalidWindowsValidationResult.statusInfo, + reason: 'The ValidationResult statusInfo messages should be the same'); + }); + + testWithoutContext('Unit testing on a regex pattern validator', () async { + const String regexPattern = + r'^(OS Version:\s*)([0-9]+\.[0-9]+\.[0-9]+)(.*)$'; + const String testStr = r''' +OS Version: 10.0.19044 N/A Build 19044 +OSz Version: 10.0.19044 N/A Build 19044 +OS 6Version: 10.0.19044 N/A Build 19044 +OxS Version: 10.0.19044 N/A Build 19044 +OS Version: 10.19044 N/A Build 19044 +OS Version: 10.x.19044 N/A Build 19044 +OS Version: 10.0.19044 N/A Build 19044 +OS Version: .0.19044 N/A Build 19044 +'''; + + final Iterable matches = + WindowsVersionValidator.validateString(regexPattern, testStr); + + expect(matches.length, 2, + reason: 'There should be only two matches for the pattern provided'); + }); +} diff --git a/packages/flutter_tools/test/host_cross_arch.shard/cache_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/cache_test.dart index 48068114289fe..4cacee849cc49 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/cache_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/cache_test.dart @@ -39,7 +39,7 @@ HostPlatform _identifyMacBinaryArch(String path) { case 'x86_64': return HostPlatform.darwin_x64; case 'arm64': - return HostPlatform.darwin_arm; + return HostPlatform.darwin_arm64; default: fail('Unexpected architecture ${match.group(1)}'); } diff --git a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart index de08721d7d453..c2e03191edd91 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart @@ -5,6 +5,7 @@ import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/build_info.dart'; import '../integration.shard/test_utils.dart'; @@ -75,7 +76,7 @@ void main() { for (final BuildMode buildMode in [BuildMode.debug, BuildMode.release]) { group('build in ${buildMode.name} mode', () { - late Directory buildPath; + late Directory outputPath; late Directory outputApp; late Directory frameworkDirectory; late Directory outputFlutterFramework; @@ -83,6 +84,9 @@ void main() { late Directory outputAppFramework; late File outputAppFrameworkBinary; late File outputPluginFrameworkBinary; + late Directory buildPath; + late Directory buildAppFrameworkDsym; + late File buildAppFrameworkDsymBinary; late ProcessResult buildResult; setUpAll(() { @@ -98,14 +102,14 @@ void main() { '--split-debug-info=foo debug info/', ], workingDirectory: projectRoot); - buildPath = fileSystem.directory(fileSystem.path.join( + outputPath = fileSystem.directory(fileSystem.path.join( projectRoot, 'build', 'ios', 'iphoneos', )); - outputApp = buildPath.childDirectory('Runner.app'); + outputApp = outputPath.childDirectory('Runner.app'); frameworkDirectory = outputApp.childDirectory('Frameworks'); outputFlutterFramework = frameworkDirectory.childDirectory('Flutter.framework'); @@ -115,6 +119,16 @@ void main() { outputAppFrameworkBinary = outputAppFramework.childFile('App'); outputPluginFrameworkBinary = frameworkDirectory.childDirectory('hello.framework').childFile('hello'); + + buildPath = fileSystem.directory(fileSystem.path.join( + projectRoot, + 'build', + 'ios', + '${sentenceCase(buildMode.name)}-iphoneos', + )); + + buildAppFrameworkDsym = buildPath.childDirectory('App.framework.dSYM'); + buildAppFrameworkDsymBinary = buildAppFrameworkDsym.childFile('Contents/Resources/DWARF/App'); }); testWithoutContext('flutter build ios builds a valid app', () { @@ -128,6 +142,8 @@ void main() { expect(outputAppFrameworkBinary, exists); expect(outputAppFramework.childFile('Info.plist'), exists); + expect(buildAppFrameworkDsymBinary.existsSync(), buildMode != BuildMode.debug); + final File vmSnapshot = fileSystem.file(fileSystem.path.join( outputAppFramework.path, 'flutter_assets', @@ -190,6 +206,25 @@ void main() { expect(aotSymbolsFound, buildMode != BuildMode.debug); }); + // dSYM is not created for a debug build so nothing to check. + if (buildMode != BuildMode.debug) { + testWithoutContext('check symbols in dSYM', () { + final ProcessResult nm = processManager.runSync( + [ + 'nm', + '--debug-syms', + '--defined-only', + '--just-symbol-name', + buildAppFrameworkDsymBinary.path, + '-arch', + 'arm64', + ], + ); + final List symbols = (nm.stdout as String).split('\n'); + expect(symbols, contains('_kDartVmSnapshotInstructions')); + }); + } + testWithoutContext('xcode_backend embed_and_thin', () { outputFlutterFramework.deleteSync(recursive: true); outputAppFramework.deleteSync(recursive: true); @@ -219,7 +254,7 @@ void main() { 'ios', 'Release-iphoneos', ), - 'TARGET_BUILD_DIR': buildPath.path, + 'TARGET_BUILD_DIR': outputPath.path, 'FRAMEWORKS_FOLDER_PATH': 'Runner.app/Frameworks', 'VERBOSE_SCRIPT_LOGGING': '1', 'FLUTTER_BUILD_MODE': 'release', diff --git a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart index 19f21e4965249..4502f380f5a3d 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart @@ -67,18 +67,18 @@ void main() { expect(result.exitCode, 0); expect(result.stdout, contains('Running pod install')); + expect(podfile.lastModifiedSync().isBefore(podfileLock.lastModifiedSync()), isTrue); - final Directory outputApp = fileSystem.directory(fileSystem.path.join( + final Directory buildPath = fileSystem.directory(fileSystem.path.join( workingDirectory, 'build', 'macos', 'Build', 'Products', buildMode, - 'flutter_gallery.app', )); - expect(podfile.lastModifiedSync().isBefore(podfileLock.lastModifiedSync()), isTrue); + final Directory outputApp = buildPath.childDirectory('flutter_gallery.app'); final Directory outputAppFramework = fileSystem.directory(fileSystem.path.join( outputApp.path, @@ -87,19 +87,19 @@ void main() { 'App.framework', )); - final File outputAppFrameworkBinary = outputAppFramework.childFile('App'); - final String archs = processManager.runSync( - ['file', outputAppFrameworkBinary.path], - ).stdout as String; - - final bool containsX64 = archs.contains('Mach-O 64-bit dynamically linked shared library x86_64'); - final bool containsArm = archs.contains('Mach-O 64-bit dynamically linked shared library arm64'); - if (buildModeLower == 'debug') { - // Only build the architecture matching the machine running this test, not both. - expect(containsX64 ^ containsArm, isTrue, reason: 'Unexpected architecture $archs'); - } else { - expect(containsX64, isTrue, reason: 'Unexpected architecture $archs'); - expect(containsArm, isTrue, reason: 'Unexpected architecture $archs'); + _checkFatBinary( + outputAppFramework.childFile('App'), + buildModeLower, + 'dynamically linked shared library', + ); + + // dSYM is not created for a debug build so nothing to check. + if (buildMode != 'Debug') { + _checkFatBinary( + buildPath.childFile('App.framework.dSYM/Contents/Resources/DWARF/App'), + buildModeLower, + 'dSYM companion file', + ); } expect(outputAppFramework.childLink('Resources'), exists); @@ -172,3 +172,19 @@ void main() { }, skip: !platform.isMacOS); // [intended] only makes sense for macos platform. } } + +void _checkFatBinary(File file, String buildModeLower, String expectedType) { + final String archs = processManager.runSync( + ['file', file.path], + ).stdout as String; + + final bool containsX64 = archs.contains('Mach-O 64-bit $expectedType x86_64'); + final bool containsArm = archs.contains('Mach-O 64-bit $expectedType arm64'); + if (buildModeLower == 'debug') { + // Only build the architecture matching the machine running this test, not both. + expect(containsX64 ^ containsArm, isTrue, reason: 'Unexpected architecture $archs'); + } else { + expect(containsX64, isTrue, reason: 'Unexpected architecture $archs'); + expect(containsArm, isTrue, reason: 'Unexpected architecture $archs'); + } +} diff --git a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart index 5dad4ab088c49..391acce9bdc8a 100644 --- a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart +++ b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart @@ -423,7 +423,7 @@ class _MyHomePageState extends State { ), Text( '$_counter', - style: Theme.of(context).textTheme.headline4, + style: Theme.of(context).textTheme.headlineMedium, ), ], ), diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index 0023ce8753b8e..158f348077639 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -68,7 +68,7 @@ void main() { ]); // Check for message only printed in verbose mode. - expect(result.stdout, contains('Running shutdown hooks')); + expect(result.stdout, contains('Shutdown hooks complete')); }); testWithoutContext('flutter config contains all features', () async { diff --git a/packages/flutter_tools/test/integration.shard/migrate_config_test.dart b/packages/flutter_tools/test/integration.shard/migrate_config_test.dart index 0792d30e2cc66..8d5a9f74182e6 100644 --- a/packages/flutter_tools/test/integration.shard/migrate_config_test.dart +++ b/packages/flutter_tools/test/integration.shard/migrate_config_test.dart @@ -105,10 +105,10 @@ project_type: app const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma'; MigrateConfig config = MigrateConfig( platformConfigs: { - SupportedPlatform.android: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.ios: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.root: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.windows: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.android: MigratePlatformConfig(platform: SupportedPlatform.android, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.ios: MigratePlatformConfig(platform: SupportedPlatform.ios, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.root: MigratePlatformConfig(platform: SupportedPlatform.root, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.windows: MigratePlatformConfig(platform: SupportedPlatform.windows, createRevision: testCreateRevision, baseRevision: testBaseRevision), }, unmanagedFiles: [ 'lib/main.dart', @@ -224,4 +224,15 @@ migration: - 'ios/Runner.xcodeproj/project.pbxproj' ''')); }); + + testUsingContext('equality compares platform', () async { + const String testCreateRevision = 'testmc9skl32nlnf23lnakcs9njr3'; + const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma'; + final MigratePlatformConfig configAndroid = MigratePlatformConfig(platform: SupportedPlatform.android, createRevision: testCreateRevision, baseRevision: testBaseRevision); + final MigratePlatformConfig configIos = MigratePlatformConfig(platform: SupportedPlatform.ios, createRevision: testCreateRevision, baseRevision: testBaseRevision); + + expect(configAndroid.equals(configIos), false); + expect(configAndroid.equals(configAndroid), true); + expect(configIos.equals(configIos), true); + }); } diff --git a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart index 887f9b7ab1457..1d1511f8d84da 100644 --- a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart +++ b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart @@ -384,7 +384,8 @@ void main() { return null; }), Barrier('Performing hot restart...'.padRight(progressMessageWidth)), - Multiple([RegExp(r'^Restarted application in [0-9]+ms.$'), 'called main', 'called paint'], handler: (String line) { + // This could look like 'Restarted application in 1,237ms.' + Multiple([RegExp(r'^Restarted application in .+m?s.$'), 'called main', 'called paint'], handler: (String line) { return 'q'; }), const Barrier('Application finished.'), diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart index c0f5e2b76fc33..4ddb5be40ada0 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart @@ -6,6 +6,8 @@ import '../test_utils.dart'; import 'project.dart'; class HotReloadProject extends Project { + HotReloadProject({super.indexHtml}); + @override final String pubspec = ''' name: test diff --git a/packages/flutter_tools/test/integration.shard/test_data/project.dart b/packages/flutter_tools/test/integration.shard/test_data/project.dart index 69be0b6d4244e..2bd9efa593b33 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/project.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:file/file.dart'; +import 'package:flutter_tools/src/web/file_generators/flutter_js.dart'; import '../test_utils.dart'; import 'deferred_components_config.dart'; @@ -19,6 +20,11 @@ const String _kDefaultHtml = ''' '''; abstract class Project { + /// Creates a flutter Project for testing. + /// + /// If passed, `indexHtml` is used as the contents of the web/index.html file. + Project({this.indexHtml = _kDefaultHtml}); + late Directory dir; String get pubspec; @@ -29,6 +35,13 @@ abstract class Project { Uri get mainDart => Uri.parse('package:test/main.dart'); + /// The contents for the index.html file of this `Project`. + /// + /// Defaults to [_kDefaultHtml] via the Project constructor. + /// + /// (Used by [HotReloadProject].) + final String indexHtml; + Future setUpIn(Directory dir) async { this.dir = dir; writeFile(fileSystem.path.join(dir.path, 'pubspec.yaml'), pubspec); @@ -45,7 +58,11 @@ abstract class Project { writeFile(fileSystem.path.join(dir.path, '.dart_tool', 'flutter_gen', 'flutter_gen.dart'), generatedFile); } deferredComponents?.setUpIn(dir); - writeFile(fileSystem.path.join(dir.path, 'web', 'index.html'), _kDefaultHtml); + + // Setup for different flutter web initializations + writeFile(fileSystem.path.join(dir.path, 'web', 'index.html'), indexHtml); + writeFile(fileSystem.path.join(dir.path, 'web', 'flutter.js'), generateFlutterJsFile()); + writeFile(fileSystem.path.join(dir.path, 'web', 'flutter_service_worker.js'), ''); writePackages(dir.path); await getPackages(dir.path); } diff --git a/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart b/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart index 314c69baf145d..b79701b141c86 100644 --- a/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart +++ b/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart @@ -44,8 +44,8 @@ void main() { testUsingContext('generated plugin registrant passes analysis', () async { await _createProject(projectDir, []); // We need a dependency so the plugin registrant is not completely empty. - await _addDependency(projectDir, 'shared_preferences', - version: '^2.0.0'); + await _editPubspecFile(projectDir, _addDependencyEditor('shared_preferences', + version: '^2.0.0')); // The plugin registrant is created on build... await _buildWebProject(projectDir); @@ -62,6 +62,7 @@ void main() { // Ensure the contents match what we expect for a non-empty plugin registrant. final String contents = registrant.readAsStringSync(); + expect(contents, contains('// @dart = 2.13')); expect(contents, contains("import 'package:shared_preferences_web/shared_preferences_web.dart';")); expect(contents, contains('void registerPlugins([final Registrar? pluginRegistrar]) {')); expect(contents, contains('SharedPreferencesPlugin.registerWith(registrar);')); @@ -77,6 +78,54 @@ void main() { ), }); + testUsingContext('generated plugin registrant passes analysis without null safety', () async { + await _createProject(projectDir, []); + // We need a dependency so the plugin registrant is not completely empty. + await _editPubspecFile(projectDir, + _composeEditors([ + _addDependencyEditor('shared_preferences', version: '^2.0.0'), + + // This turns null safety off + _setDartSDKVersionEditor('>=2.11.0 <3.0.0'), + ])); + + // The generated main.dart file has a bunch of stuff that is invalid without null safety, so + // replace it with a no-op dummy main file. We aren't testing it in this scenario anyway. + await _replaceMainFile(projectDir, 'void main() {}'); + + // The plugin registrant is created on build... + await _buildWebProject(projectDir); + + // Find the web_plugin_registrant, now that it lives outside "lib": + final Directory buildDir = projectDir + .childDirectory('.dart_tool/flutter_build') + .listSync() + .firstWhere((FileSystemEntity entity) => entity is Directory) as Directory; + + // Ensure the file exists, and passes analysis. + final File registrant = buildDir.childFile('web_plugin_registrant.dart'); + expect(registrant, exists); + await _analyzeEntity(registrant); + + // Ensure the contents match what we expect for a non-empty plugin registrant. + final String contents = registrant.readAsStringSync(); + expect(contents, contains('// @dart = 2.13')); + expect(contents, contains("import 'package:shared_preferences_web/shared_preferences_web.dart';")); + expect(contents, contains('void registerPlugins([final Registrar? pluginRegistrar]) {')); + expect(contents, contains('SharedPreferencesPlugin.registerWith(registrar);')); + expect(contents, contains('registrar.registerMessageHandler();')); + }, overrides: { + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + + testUsingContext('(no-op) generated plugin registrant passes analysis', () async { await _createProject(projectDir, []); // No dependencies on web plugins this time! @@ -110,8 +159,8 @@ void main() { // See: https://github.com/dart-lang/dart-services/pull/874 testUsingContext('generated plugin registrant for dartpad is created on pub get', () async { await _createProject(projectDir, []); - await _addDependency(projectDir, 'shared_preferences', - version: '^2.0.0'); + await _editPubspecFile(projectDir, + _addDependencyEditor('shared_preferences', version: '^2.0.0')); // The plugin registrant for dartpad is created on flutter pub get. await _doFlutterPubGet(projectDir); @@ -154,10 +203,12 @@ void main() { // With the above lint rule added, we want to ensure that the `generated_plugin_registrant.dart` // file does not fail analysis (this is a regression test - an ignore was // added to cover this case). - await _addDependency( + await _editPubspecFile( projectDir, - 'test_web_plugin_with_a_purposefully_extremely_long_package_name', - path: '../test_plugin', + _addDependencyEditor( + 'test_web_plugin_with_a_purposefully_extremely_long_package_name', + path: '../test_plugin', + ) ); // The plugin registrant is only created after a build... await _buildWebProject(projectDir); @@ -255,32 +306,76 @@ Future _createProject(Directory dir, List createArgs) async { ]); } -Future _addDependency( +typedef PubspecEditor = void Function(List pubSpecContents); + +Future _editPubspecFile( Directory projectDir, - String package, { - String? version, - String? path, -}) async { + PubspecEditor editor, +) async { + final File pubspecYaml = projectDir.childFile('pubspec.yaml'); + expect(pubspecYaml, exists); + + final List lines = await pubspecYaml.readAsLines(); + editor(lines); + await pubspecYaml.writeAsString(lines.join('\n')); +} + +Future _replaceMainFile(Directory projectDir, String fileContents) async { + final File mainFile = projectDir.childDirectory('lib').childFile('main.dart'); + await mainFile.writeAsString(fileContents); +} + +PubspecEditor _addDependencyEditor(String packageToAdd, {String? version, String? path}) { assert(version != null || path != null, 'Need to define a source for the package.'); assert(version == null || path == null, 'Cannot only load a package from path or from Pub, not both.'); + void editor(List lines) { + for (int i = 0; i < lines.length; i++) { + final String line = lines[i]; + if (line.startsWith('dependencies:')) { + lines.insert( + i + 1, + ' $packageToAdd: ${version ?? '\n' + ' path: $path'}'); + break; + } + } + } + return editor; +} - final File pubspecYaml = projectDir.childFile('pubspec.yaml'); - expect(pubspecYaml, exists); +PubspecEditor _setDartSDKVersionEditor(String version) { + void editor(List lines) { + for (int i = 0; i < lines.length; i++) { + final String line = lines[i]; + if (line.startsWith('environment:')) { + for (i++; i < lines.length; i++) { + final String innerLine = lines[i]; + final String sdkLine = " sdk: '$version'"; + if(innerLine.isNotEmpty && !innerLine.startsWith(' ')) { + lines.insert(i, sdkLine); + break; + } + if(innerLine.startsWith(' sdk:')) { + lines[i] = sdkLine; + break; + } + } + break; + } + } + } + return editor; +} - final List lines = await pubspecYaml.readAsLines(); - for (int i = 0; i < lines.length; i++) { - final String line = lines[i]; - if (line.startsWith('dependencies:')) { - lines.insert( - i + 1, - ' $package: ${version ?? '\n' - ' path: $path'}'); - break; +PubspecEditor _composeEditors(Iterable editors) { + void composedEditor(List lines) { + for (final PubspecEditor editor in editors) { + editor(lines); } } - await pubspecYaml.writeAsString(lines.join('\n')); + return composedEditor; } Future _addAnalysisOptions( diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index bef96e194919d..d292e99c36aae 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart @@ -154,7 +154,7 @@ void testUsingContext( ); }, overrides: { // This has to go here so that runInContext will pick it up when it tries - // to do bot detection before running the closure. This is important + // to do bot detection before running the closure. This is important // because the test may be giving us a fake HttpClientFactory, which may // throw in unexpected/abnormal ways. // If a test needs a BotDetector that does not always return true, it diff --git a/packages/flutter_tools/test/web.shard/chrome_test.dart b/packages/flutter_tools/test/web.shard/chrome_test.dart index 378a699a8866c..1e4e54bb27e38 100644 --- a/packages/flutter_tools/test/web.shard/chrome_test.dart +++ b/packages/flutter_tools/test/web.shard/chrome_test.dart @@ -228,7 +228,7 @@ void main() { }); testWithoutContext('can launch x86_64 Chrome on ARM macOS', () async { - final OperatingSystemUtils macOSUtils = FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm); + final OperatingSystemUtils macOSUtils = FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64); final ChromiumLauncher chromiumLauncher = ChromiumLauncher( fileSystem: fileSystem, platform: platform, @@ -267,7 +267,7 @@ void main() { }); testWithoutContext('can launch ARM Chrome natively on ARM macOS when installed', () async { - final OperatingSystemUtils macOSUtils = FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm); + final OperatingSystemUtils macOSUtils = FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64); final ChromiumLauncher chromiumLauncher = ChromiumLauncher( fileSystem: fileSystem, platform: platform, diff --git a/packages/flutter_tools/test/web.shard/expression_evaluation_web_test.dart b/packages/flutter_tools/test/web.shard/expression_evaluation_web_test.dart index 3f4564f9f2183..737f5e7d4d883 100644 --- a/packages/flutter_tools/test/web.shard/expression_evaluation_web_test.dart +++ b/packages/flutter_tools/test/web.shard/expression_evaluation_web_test.dart @@ -23,6 +23,7 @@ void main() { flutter = FlutterRunTestDriver(tempDir); flutter.stdout.listen((String line) { expect(line, isNot(contains('Unresolved uri:'))); + expect(line, isNot(contains('No module for'))); }); }); diff --git a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart index ba26e119b7f35..ebf23327acfe1 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart @@ -11,11 +11,22 @@ import '../integration.shard/test_driver.dart'; import '../integration.shard/test_utils.dart'; import '../src/common.dart'; -void main() { +import 'test_data/hot_reload_index_html_samples.dart'; + +void main() async { + await _testProject(HotReloadProject()); // default + await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsCallback), name: 'flutter.js (callback)'); + await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsPromisesFull), name: 'flutter.js (promises)'); + await _testProject(HotReloadProject(indexHtml: indexHtmlFlutterJsPromisesShort), name: 'flutter.js (promises, short)'); + await _testProject(HotReloadProject(indexHtml: indexHtmlNoFlutterJs), name: 'No flutter.js'); +} + +Future _testProject(HotReloadProject project, {String name = 'Default'}) async { late Directory tempDir; - final HotReloadProject project = HotReloadProject(); late FlutterRunTestDriver flutter; + final String testName = 'Hot reload (index.html: $name)'; + setUp(() async { tempDir = createResolvedTempDirectorySync('hot_reload_test.'); await project.setUpIn(tempDir); @@ -28,12 +39,12 @@ void main() { tryToDelete(tempDir); }); - testWithoutContext('hot restart works without error', () async { + testWithoutContext('$testName: hot restart works without error', () async { await flutter.run(chrome: true, additionalCommandArgs: ['--verbose', '--web-renderer=html']); await flutter.hotRestart(); }); - testWithoutContext('newly added code executes during hot restart', () async { + testWithoutContext('$testName: newly added code executes during hot restart', () async { final Completer completer = Completer(); final StreamSubscription subscription = flutter.stdout.listen((String line) { if (line.contains('(((((RELOAD WORKED)))))')) { @@ -50,7 +61,7 @@ void main() { } }); - testWithoutContext('newly added code executes during hot restart - canvaskit', () async { + testWithoutContext('$testName: newly added code executes during hot restart - canvaskit', () async { final Completer completer = Completer(); final StreamSubscription subscription = flutter.stdout.listen((String line) { if (line.contains('(((((RELOAD WORKED)))))')) { @@ -66,5 +77,5 @@ void main() { } finally { await subscription.cancel(); } - }, skip: true); // Skipping for https://github.com/flutter/flutter/issues/85043. + }, skip: true); // Skipped for https://github.com/flutter/flutter/issues/110879. } diff --git a/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart b/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart index fc78c098773a0..1e7386de36eaf 100644 --- a/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart +++ b/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:dwds/dwds.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; @@ -13,10 +11,10 @@ import 'package:flutter_tools/src/isolated/sdk_web_configuration.dart'; import '../src/common.dart'; void main() { - FileSystem fileSystem; + late FileSystem fileSystem; group('Flutter SDK configuration for web', () { - SdkConfiguration configuration; + late SdkConfiguration configuration; setUp(() async { fileSystem = MemoryFileSystem.test(); diff --git a/packages/flutter_tools/test/web.shard/test_data/hot_reload_index_html_samples.dart b/packages/flutter_tools/test/web.shard/test_data/hot_reload_index_html_samples.dart new file mode 100644 index 0000000000000..9812b34a9cb07 --- /dev/null +++ b/packages/flutter_tools/test/web.shard/test_data/hot_reload_index_html_samples.dart @@ -0,0 +1,179 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains a bunch of different index.html "styles" that can be written +// by Flutter Web users. +// This should be somewhat kept in sync with the different index.html files present +// in `flutter/dev/integration_tests/web/web`. +// @see https://github.com/flutter/flutter/tree/master/dev/integration_tests/web/web + +/// index_with_flutterjs_entrypoint_loaded.html +String indexHtmlFlutterJsCallback = _generateFlutterJsIndexHtml(''' + window.addEventListener('load', function(ev) { + // Download main.dart.js + _flutter.loader.loadEntrypoint({ + onEntrypointLoaded: onEntrypointLoaded, + serviceWorker: { + serviceWorkerVersion: serviceWorkerVersion, + } + }); + // Once the entrypoint is ready, do things! + async function onEntrypointLoaded(engineInitializer) { + const appRunner = await engineInitializer.initializeEngine(); + appRunner.runApp(); + } + }); +'''); + +/// index_with_flutterjs_short.html +String indexHtmlFlutterJsPromisesShort = _generateFlutterJsIndexHtml(''' + window.addEventListener('load', function(ev) { + // Download main.dart.js + _flutter.loader.loadEntrypoint({ + serviceWorker: { + serviceWorkerVersion: serviceWorkerVersion, + } + }).then(function(engineInitializer) { + return engineInitializer.autoStart(); + }); + }); +'''); + +/// index_with_flutterjs.html +String indexHtmlFlutterJsPromisesFull = _generateFlutterJsIndexHtml(''' + window.addEventListener('load', function(ev) { + // Download main.dart.js + _flutter.loader.loadEntrypoint({ + serviceWorker: { + serviceWorkerVersion: serviceWorkerVersion, + } + }).then(function(engineInitializer) { + return engineInitializer.initializeEngine(); + }).then(function(appRunner) { + return appRunner.runApp(); + }); + }); +'''); + +/// index_without_flutterjs.html +String indexHtmlNoFlutterJs = ''' + + + + + + + + Web Test + + + + + + + + + + + +'''; + +// Generates the scaffolding of an index.html file, with a configurable `initScript`. +String _generateFlutterJsIndexHtml(String initScript) => ''' + + + + + + + + Integration test. App load with flutter.js and onEntrypointLoaded API + + + + + + + + + + + + + +'''; diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index 9331cf8c058cb..a61892f291fda 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -32,6 +32,6 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0ce9 +# PUBSPEC CHECKSUM: 32eb diff --git a/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart b/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart index cff0d833a7b5a..200e0fb8294ba 100644 --- a/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart +++ b/packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart @@ -424,7 +424,7 @@ class FuchsiaRemoteConnection { }) async { if (!_dartVmCache.containsKey(uri)) { // When raising an HttpException this means that there is no instance of - // the Dart VM to communicate with. The TimeoutException is raised when + // the Dart VM to communicate with. The TimeoutException is raised when // the Dart VM instance is shut down in the middle of communicating. try { final DartVm dartVm = await DartVm.connect(uri, timeout: timeout); diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 654fef433104c..bb3011cbad5be 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -10,16 +10,16 @@ dependencies: process: 4.2.4 vm_service: 9.3.0 - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.21.4 + test: 1.21.5 - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,7 +27,7 @@ dev_dependencies: convert: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,16 +51,16 @@ dev_dependencies: stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: a70b +# PUBSPEC CHECKSUM: 9d0f diff --git a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m index d3bdcc6604dd0..820497d405ec0 100644 --- a/packages/integration_test/example/ios/RunnerTests/RunnerTests.m +++ b/packages/integration_test/example/ios/RunnerTests/RunnerTests.m @@ -67,7 +67,7 @@ - (void)testMethodNamesFromDartTests { XCTAssertEqualObjects([FLTIntegrationTestRunner testCaseNameFromDartTestName:@"VALIDATE multi-point 🚀 UNICODE123: 😁"], @"testValidateMultiPointUnicode123"); XCTAssertEqualObjects([FLTIntegrationTestRunner - testCaseNameFromDartTestName:@"!UPPERCASE:\\ lower_seperate?"], @"testUppercaseLowerSeperate"); + testCaseNameFromDartTestName:@"!UPPERCASE:\\ lower_separate?"], @"testUppercaseLowerSeparate"); } - (void)testDuplicatedDartTests { diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index b63c2401fcc78..cdbc482afcc19 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -27,14 +27,14 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.21.4 + test: 1.21.5 pedantic: 1.11.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 46.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 4.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 47.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 4.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -44,8 +44,8 @@ dev_dependencies: coverage: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,17 +71,17 @@ dev_dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.4.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.4.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 9.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d5d +# PUBSPEC CHECKSUM: 2362 diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 5d0554b7b5a30..69d151daabb58 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -20,9 +20,9 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: 2a27 +# PUBSPEC CHECKSUM: 2b28 diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index f0147564557de..566929aa7fb7e 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: collection: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -33,9 +33,9 @@ dependencies: string_scanner: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.4.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -47,4 +47,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: cb0e +# PUBSPEC CHECKSUM: ad11