diff --git a/.ci.yaml b/.ci.yaml index cbd47a3a03f95..ce3daf30614c0 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -26,6 +26,7 @@ platform_properties: cores: "8" device_type: none ignore_flakiness: "true" + linux: properties: dependencies: >- @@ -35,6 +36,7 @@ platform_properties: os: Ubuntu cores: "8" device_type: none + # The current android emulator config names can be found here: # https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/android/avd/proto # You may use those names for the android_virtual_device version. You may find the @@ -58,6 +60,7 @@ platform_properties: cores: "8" device_type: none kvm: "1" + # linux_android_emu_unstable is intended to be how flutter-android proves the stability # of new combinations of dependencies. linux_android_emu_unstable: @@ -77,6 +80,7 @@ platform_properties: cores: "8" device_type: none kvm: "1" + linux_build_test: properties: dependencies: >- @@ -88,16 +92,6 @@ platform_properties: os: Ubuntu cores: "8" device_type: none - linux_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"}, - {"dependency": "curl", "version": "version:7.64.0"} - ] - os: Linux - device_type: "msm8952" linux_pixel_7pro: properties: @@ -142,12 +136,13 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_arm64: properties: contexts: >- @@ -158,13 +153,14 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: arm64 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_benchmark: properties: contexts: >- @@ -177,13 +173,14 @@ platform_properties: ] device_type: none mac_model: "Macmini8,1" - os: Mac-14 + os: Mac-14|Mac-15.5 tags: > ["devicelab", "hostonly", "mac"] $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_x64: properties: contexts: >- @@ -194,13 +191,14 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: x86 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_build_test: properties: contexts: >- @@ -212,34 +210,13 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: x86 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } - mac_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14 - cpu: x86 - device_type: "msm8952" - mac_arm64_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14 - cpu: arm64 - device_type: "msm8952" mac_mokey: properties: @@ -249,9 +226,10 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: x86 device_type: "mokey" + mac_arm64_mokey: properties: dependencies: >- @@ -259,20 +237,10 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v1"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: arm64 device_type: "mokey" - mac_pixel_7pro: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14 - cpu: x86 - device_type: "Pixel 7 Pro" mac_ios: properties: contexts: >- @@ -284,12 +252,13 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_x64_ios: properties: contexts: >- @@ -301,13 +270,14 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 cpu: x86 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + mac_arm64_ios: properties: contexts: >- @@ -319,33 +289,25 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "none"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 cpu: arm64 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" } + windows: properties: os: Windows-10 device_type: none + windows_arm64: properties: - # The arch can be removed after https://github.com/flutter/flutter/issues/135722. arch: arm os: Windows cpu: arm64 - windows_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Windows-10 - device_type: "msm8952" + windows_mokey: properties: dependencies: >- @@ -394,7 +356,7 @@ targets: bringup: true # https://github.com/flutter/flutter/issues/164591 presubmit: false recipe: flutter/coverage - timeout: 120 + timeout: 90 enabled_branches: # Don't run this on release branches - master @@ -584,18 +546,41 @@ targets: # to GCS", and conditionally on the "master" channel will also deploy the docs # to Firebase (https://main-api.flutter.dev/). # - # See "Linux docs_deploy_stable" for how the docs are deployed to stable API. + # See "Linux docs_generate_release" for how docs are built (but not published) + # and "Linux docs_deploy_stable" for how docs deployed for the stable branch + # (we do not deploy docs for beta). - name: Linux docs_publish recipe: flutter/docs presubmit: false backfill: false - # This means "allow this to be scheduled by the release/release_builder" - # recipe. Normally we'd use "schedule: true", but that *also* means "do not - # run this in normal presubmit/postsubmit", and we do want it to run in - # postsubmit for the "master" channel. Sorry. - # - # See https://github.com/flutter/flutter/issues/168709 for details. - schedule_during_release_override: true + enabled_branches: + - master + timeout: 60 + dimensions: + os: "Linux" + properties: + cores: "32" + dependencies: >- + [ + {"dependency": "dashing", "version": "0.4.0"}, + {"dependency": "firebase", "version": "v11.0.1"} + ] + tags: > + ["framework", "hostonly", "linux"] + validation: docs + validation_name: Docs + firebase_project: main-docs-flutter-prod + release_ref: refs/heads/master + drone_dimensions: + - os=Linux + + - name: Linux docs_generate_release + recipe: flutter/docs + scheduler: release + presubmit: false + postsubmit: false + enabled_branches: + - flutter-\d+\.\d+-candidate\.\d+ timeout: 60 dimensions: os: "Linux" @@ -610,14 +595,45 @@ targets: ["framework", "hostonly", "linux"] validation: docs validation_name: Docs + # TODO(matanlurey): Neither of these properties are actually used, since + # the branch name is not "master", but if they are removed, the recipe + # will fail. See https://github.com/flutter/flutter/issues/169108. firebase_project: main-docs-flutter-prod release_ref: refs/heads/master drone_dimensions: - os=Linux + + # This step runs on the release channel "stable", after the same commit SHA + # has been run and built by Linux flutter_release_builder as part of a release + # candidate branch (i.e. /flutter-\d+\.\d+-candidate\.\d+/) in the previous + # target, "Linux docs_generate_release". + - name: Linux docs_deploy_stable + recipe: flutter/docs + scheduler: release + presubmit: false + postsubmit: false + enabled_branches: + - stable + timeout: 60 + properties: + cores: "32" + dependencies: >- + [ + {"dependency": "dashing", "version": "0.4.0"}, + {"dependency": "firebase", "version": "v11.0.1"} + ] + tags: > + ["framework", "hostonly", "linux"] + validation: docs_deploy + validation_name: Docs_deploy + firebase_project: docs-flutter-dev + drone_dimensions: + - os=Linux + - name: Linux docs_test recipe: flutter/flutter_drone - timeout: 90 # https://github.com/flutter/flutter/issues/120901 + timeout: 30 properties: cores: "32" dependencies: >- @@ -2246,7 +2262,8 @@ targets: - name: Linux web_tool_tests recipe: flutter/flutter_drone - timeout: 60 + bringup: true # Flaky https://github.com/flutter/flutter/issues/169574 + timeout: 90 # https://github.com/flutter/flutter/issues/169634 properties: dependencies: >- [ @@ -2261,7 +2278,7 @@ targets: ["framework", "hostonly", "shard", "linux"] # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 presubmit_max_attempts: "2" - test_timeout_secs: "3600" # https://github.com/flutter/flutter/issues/162714 + test_timeout_secs: "5400" # https://github.com/flutter/flutter/issues/162714 runIf: - dev/** - packages/flutter_tools/** @@ -5389,7 +5406,7 @@ targets: bringup: true timeout: 60 properties: - os: Mac-15 + os: Mac-15.3 device_os: iOS-18.4 $flutter/osx_sdk : >- { @@ -5458,7 +5475,7 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery__transition_perf_e2e_ios drone_dimensions: > - ["device_os=iOS-17|iOS-18","os=Mac-14", "cpu=x86"] + ["device_os=iOS-17|iOS-18","os=Mac-14|Mac-15.5", "cpu=x86"] - name: Mac_ios animated_blur_backdrop_filter_perf_ios__timeline_summary recipe: devicelab/devicelab_drone @@ -6997,30 +7014,3 @@ targets: ["framework", "hostonly", "shard", "windows"] drone_dimensions: - os=Windows - - # This step runs on the release channel "stable", after the same commit SHA - # has been run and built by Linux flutter_release_builder as part of a release - # candidate branch (i.e. /flutter-\d+\.\d+-candidate\.\d+/) in the previous - # target, "Linux docs_publish". - - name: Linux docs_deploy_stable - recipe: flutter/docs - scheduler: release - bringup: true - enabled_branches: - - stable - presubmit: false - timeout: 60 - properties: - cores: "32" - dependencies: >- - [ - {"dependency": "dashing", "version": "0.4.0"}, - {"dependency": "firebase", "version": "v11.0.1"} - ] - tags: > - ["framework", "hostonly", "linux"] - validation: docs_deploy - validation_name: Docs_deploy - firebase_project: docs-flutter-dev - drone_dimensions: - - os=Linux diff --git a/.github/ISSUE_TEMPLATE/08_first_party_packages.yml b/.github/ISSUE_TEMPLATE/08_first_party_packages.yml index dc8e3f7c74d8d..027928d244a98 100644 --- a/.github/ISSUE_TEMPLATE/08_first_party_packages.yml +++ b/.github/ISSUE_TEMPLATE/08_first_party_packages.yml @@ -31,14 +31,10 @@ body: - animations - camera - cross_file - - css_colors - espresso - extension_google_sign_in_as_googleapis_auth - file_selector - - flutter_adaptive_scaffold - - flutter_image - flutter_lints - - flutter_markdown - flutter_migrate - flutter_plugin_android_lifecycle - flutter_svg @@ -52,11 +48,9 @@ body: - image_picker - in_app_purchase - interactive_media_ads - - ios_platform_images - local_auth - metrics_center - multicast_dns - - palette_generator - path_parsing - path_provider - pigeon diff --git a/.github/workflows/tool-test-general.yml b/.github/workflows/tool-test-general.yml new file mode 100644 index 0000000000000..898061327b0ff --- /dev/null +++ b/.github/workflows/tool-test-general.yml @@ -0,0 +1,93 @@ +name: Tool tests general - experiment + +on: + pull_request: + branches: [master] + paths: + - '.github/workflows/tool-test-general.yml' + - 'dev/**' + - 'packages/flutter_tools/**' + - 'bin/**' + - '.ci.yaml' + - 'engine/**' + - 'DEPS' + push: + branches: [master] + +jobs: + Linux_tool-tests-general: + permissions: + contents: read + + runs-on: ubuntu-latest + + steps: + # Real checkout on github actions for pull requests + - name: Checkout code (non-act pull_request) + uses: actions/checkout@v4 + if: github.event_name == 'pull_request' && !env.ACT + with: + fetch-depth: 0 + fetch-tags: true + # Checkout the PR; not the merge commit - we need to describe tags + ref: ${{ github.event.pull_request.head.sha }} + + # Real checkout on github actions for post submit + - name: Checkout code (non-act push) + uses: actions/checkout@v4 + if: github.event_name == 'push' && !env.ACT + with: + fetch-depth: 0 + fetch-tags: true + # Checkout the PR; not the merge commit - we need to describe tags + ref: ${{ github.event.pull_request.head.sha }} + + # Fake checkout if running locally + - name: Checkout code (act local) + uses: actions/checkout@v4 + if: env.ACT + + # If this is a branch / pr NOT on fluter/flutter, set the remote upstream + # so the flutter tool can figure out the version + - name: Set upstream (if not flutter/flutter) + if: github.repository != 'flutter/flutter' && !env.ACT + run: | + git remote add upstream https://github.com/flutter/flutter.git + git fetch --all --tags + + # If running locally; install the JDK - Github runners have everything on them + - name: Set up our JDK environment + if: env.ACT + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 + with: + java-version: '21' + distribution: 'temurin' + + # If running locally; install Android SDK tools - Github runners have everything on them + - name: Setup Android SDK + if: env.ACT + uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 + with: + cmdline-tools-version: 13114758 + + # If running locally; install Android SDK - Github runners have everything on them + - name: install android + if: env.ACT + run: | + sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0" + + - name: Add `flutter` to the PATH + run: | + echo "$PWD/bin" >> "$GITHUB_PATH" + + - name: Flutter Doctor + run: | + flutter doctor + + - name: update-packages + run: | + flutter update-packages + + - name: Tool Test + run: | + SHARD=tool_tests SUBSHARD=general dart --enable-asserts dev/bots/test.dart diff --git a/.gitignore b/.gitignore index 73728cebbfccf..04b7cdcca4f77 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,13 @@ .history .svn/ +# As packages are no longer pinned, we use a lockfile for testing locally. +# When unpinning packages, Using lockfiles ensures that failures in PRs are +# actually due to those PRs, not due to a package being updated. +!/pubspec.lock +!packages/flutter_tools/pubspec.lock +!packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.lock + # IntelliJ related *.iml *.ipr @@ -63,7 +70,6 @@ analysis_benchmark.json # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies **/generated_plugin_registrant.dart .packages diff --git a/CHANGELOG.md b/CHANGELOG.md index 5182d10ee9f58..515bcd74043f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,21 @@ docs/releases/Hotfix-Documentation-Best-Practices.md --> ## Flutter 3.32 Changes +### [3.32.2](https://github.com/flutter/flutter/releases/tag/3.32.2) + +- [flutter/169772](https://github.com/flutter/flutter/pull/169772) - Configuration changes for Flutter's CI to run tests on Linux instead of Windows when not otherwise required. +- [flutter/169630](https://github.com/flutter/flutter/pull/169630) - Fixes issue where flavored Android packages may not successfully build on Windows repeatedly until the next clean. +- [flutter/169912](https://github.com/flutter/flutter/pull/169912) - Splits Flutter CI task for publishing API docs into one build step and one deploy step. + ### [3.32.1](https://github.com/flutter/flutter/releases/tag/3.32.1) + +- [flutter/156793](https://github.com/flutter/flutter/issues/156793) - Fixes flaky crash when targeting web applications via IDEs using the DAP. +- [flutter/168849](https://github.com/flutter/flutter/issues/168849) - Fixes an issue rendering wide gamut images. +- [flutter/168846](https://github.com/flutter/flutter/issues/168846) - Fixes an issue displaying the wrong icons in the widget inspector for some apps. +- [flutter/167011](https://github.com/flutter/flutter/pull/167011) - Fixes Flutter Android builds for apps which use plugins with old Android Gradle Plugin versions. +- [flutter/169101](https://github.com/flutter/flutter/issues/169101) - Reduces the cost of running the (sometimes flaky) Linux fuchsia_test on release branches. +- [flutter/169318](https://github.com/flutter/flutter/issues/169318) - Fixed a bug where the flutter tool crash reporting did not include what plugins were being used by the current project. +- [flutter/169160](https://github.com/flutter/flutter/issues/169160) Fixed a bug where `appFlavor` is null after hot restarts or during `flutter test`. - [flutter/167011](https://github.com/flutter/flutter/pull/167011) [Android] Fix regression in NDK version checking for projects with old AGP versions. - [flutter/168847](https://github.com/flutter/flutter/pull/168847) [Widget Inspector] Fix missing cupertino icon in on-device inspector. diff --git a/DEPS b/DEPS index 19a13547b99d9..8894921fc2ae2 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '82d326fc2148181e8d9ca848b17237fa4db75331', + 'skia_revision': 'c810c9ba87fec88a85ad57f35a4207f14d161cff', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. @@ -56,29 +56,29 @@ vars = { # Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS # You can use //tools/dart/create_updated_flutter_deps.py to produce # updated revision list of existing dependencies. - 'dart_revision': '6aeb798bdbe27e6e6c5ee533dca392404ca496ce', + 'dart_revision': '239174405ad089da5f6063c8c002efbbd354b0b0', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py - 'dart_ai_rev': '93a9191b6eed79d24fc5d3ec9b514f71c888fc41', + 'dart_ai_rev': '2a5eb30492c4231624ae954e93aa1491e4aca84f', 'dart_binaryen_rev': 'b4bdcc33115b31758c56b83bb9de4642c411a042', 'dart_boringssl_rev': 'a934ee9e1fe4397e682f9f18b1f4f061d7400f9d', 'dart_core_rev': '635dfa32c261ba078438b74de397f2207904ca78', - 'dart_devtools_rev': '21132242f6e12b26e3d9c0f06109361f7e519608', - 'dart_ecosystem_rev': '815d4ba2e7d11f8695a26f6cbe1262e3b8ff8d0d', + 'dart_devtools_rev': '73eadd3be6eff2ddd9c7673f855f327a80111ebb', + 'dart_ecosystem_rev': '8cebaf083e9107995811f1f0d2b40b570a0bbb66', 'dart_http_rev': 'e70a41b8b841ada9ba124b3b9e1a4d3c525b8bf9', 'dart_i18n_rev': 'e44af5483a051d546716b6aa3a57e478c59a5d8d', 'dart_libprotobuf_rev': '24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb', 'dart_perfetto_rev': '13ce0c9e13b0940d2476cd0cff2301708a9a2e2b', 'dart_protobuf_gn_rev': 'ca669f79945418f6229e4fef89b666b2a88cbb10', - 'dart_protobuf_rev': 'd940c8de905439e292770ccf6c546477ae566462', + 'dart_protobuf_rev': 'c69077d83ce5a66d21127019f45b81bcd1e777c4', 'dart_pub_rev': '59406faad8959e332da98260bab894feb8500908', 'dart_sync_http_rev': 'dc54465f07d9652875deeade643256dafa2fbc6c', - 'dart_tools_rev': 'be0bd20c803377063c45904512f272fdda94e8c3', + 'dart_tools_rev': '04c684955a9ffdfbafff07fcad62840658efe283', 'dart_vector_math_rev': '13f185f7e97d559e003f5ac79201da12f9a01049', 'dart_web_rev': 'f1becf07db9faa56559d2844c3c6d430dc9b37de', - 'dart_webdev_rev': '5dbb30ebc695ad2ecc01fa8eae4e0494c199e1bc', - 'dart_webdriver_rev': 'f52afbf72895ae980bd4129d877305c2182d6cbc', + 'dart_webdev_rev': '64492b2da3d8b5ec30c9ea1fa0c83fb7b69c90c6', + 'dart_webdriver_rev': 'b8f511d7719e2ae2c21eb4d94f68564eee32cbe2', 'dart_webkit_inspection_protocol_rev': 'effa75205516757795683d527c3dea9546eb0c32', 'ocmock_rev': 'c4ec0e3a7a9f56cfdbd0aa01f4f97bb4b75c5ef8', # v3.7.1 @@ -305,7 +305,7 @@ deps = { Var('chromium_git') + '/external/github.com/WebAssembly/binaryen.git@b4bdcc33115b31758c56b83bb9de4642c411a042', 'engine/src/flutter/third_party/dart/third_party/devtools': - {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:21132242f6e12b26e3d9c0f06109361f7e519608'}]}, + {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:73eadd3be6eff2ddd9c7673f855f327a80111ebb'}]}, 'engine/src/flutter/third_party/dart/third_party/pkg/ai': Var('dart_git') + '/ai.git' + '@' + Var('dart_ai_rev'), @@ -317,7 +317,7 @@ deps = { Var('dart_git') + '/dart_style.git@100db45075abdd66fd8788b205243e90ff0595df', 'engine/src/flutter/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@e38f392163a4738a21024acd370d104e0efe72f0', + Var('dart_git') + '/dartdoc.git@4ceea6b8240bf1dd9694a170368264e40c67d66b', 'engine/src/flutter/third_party/dart/third_party/pkg/ecosystem': Var('dart_git') + '/ecosystem.git' + '@' + Var('dart_ecosystem_rev'), @@ -350,7 +350,7 @@ deps = { Var('dart_git') + '/external/github.com/simolus3/tar.git@5a1ea943e70cdf3fa5e1102cdbb9418bd9b4b81a', 'engine/src/flutter/third_party/dart/third_party/pkg/test': - Var('dart_git') + '/test.git@42a6d333d96b4b0964d356b9a29ca47ccdb43691', + Var('dart_git') + '/test.git@e2ddae9f2943eac2f6c5caf30bc6316e4bff4a8c', 'engine/src/flutter/third_party/dart/third_party/pkg/tools': Var('dart_git') + '/tools.git' + '@' + Var('dart_tools_rev'), @@ -480,7 +480,7 @@ deps = { }, 'engine/src/flutter/third_party/expat': - Var('chromium_git') + '/external/github.com/libexpat/libexpat.git' + '@' + '654d2de0da85662fcc7644a7acd7c2dd2cfb21f0', + Var('chromium_git') + '/external/github.com/libexpat/libexpat.git' + '@' + '8e49998f003d693213b538ef765814c7d21abada', 'engine/src/flutter/third_party/freetype2': Var('flutter_git') + '/third_party/freetype2' + '@' + 'bfc3453fdc85d87b45c896f68bf2e49ebdaeef0a', @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'nC9hLWjYVlChDTEPhMpsRnSYKFDw4zfIRl2sHkX3yCIC' + 'version': 'Dueykg3VpLT5D_jSG3jtXPhsEwLhB-XGPqiZkbGcBBMC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/TESTOWNERS b/TESTOWNERS index b6d9273e2d2a1..a6d3556272556 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -311,8 +311,8 @@ /dev/devicelab/bin/tasks/android_display_cutout.dart @reidbaker @flutter/android ## Host only framework tests -# Linux docs_deploy_beta # Linux docs_deploy_stable +# Linux docs_generate_release # Linux docs_publish /dev/bots/docs.sh @Piinks @flutter/framework # Linux packages_autoroller diff --git a/bin/dart.bat b/bin/dart.bat index 62447d98e8841..61942a441eeb9 100644 --- a/bin/dart.bat +++ b/bin/dart.bat @@ -15,6 +15,19 @@ SETLOCAL FOR %%i IN ("%~dp0..") DO SET FLUTTER_ROOT=%%~fi +REM Detect which PowerShell executable is available on the host +REM PowerShell version <= 5: PowerShell.exe +REM PowerShell version >= 6: pwsh.exe +WHERE /Q pwsh.exe && ( + SET powershell_executable=pwsh.exe +) || WHERE /Q PowerShell.exe && ( + SET powershell_executable=PowerShell.exe +) || ( + ECHO Error: PowerShell executable not found. 1>&2 + ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 + EXIT /B 1 +) + REM Include shared scripts in shared.bat SET shared_bin=%FLUTTER_ROOT%/bin/internal/shared.bat CALL "%shared_bin%" diff --git a/bin/flutter-dev.bat b/bin/flutter-dev.bat index c74b9747dc98e..51d6a2e97d6a2 100644 --- a/bin/flutter-dev.bat +++ b/bin/flutter-dev.bat @@ -27,7 +27,26 @@ REM If available, add location of bundled mingit to PATH SET mingit_path=%FLUTTER_ROOT%\bin\mingit\cmd IF EXIST "%mingit_path%" SET PATH=%PATH%;%mingit_path% -REM We test if Git is available on the Host as we run git in shared.bat +REM Test if Git is available on the host +WHERE /Q git +IF "%ERRORLEVEL%" NEQ "0" ( + ECHO Error: Unable to find git in your PATH. + EXIT /B 1 +) + +REM Detect which PowerShell executable is available on the host +REM PowerShell version <= 5: PowerShell.exe +REM PowerShell version >= 6: pwsh.exe +WHERE /Q pwsh.exe && ( + SET powershell_executable=pwsh.exe +) || WHERE /Q PowerShell.exe && ( + SET powershell_executable=PowerShell.exe +) || ( + ECHO Error: PowerShell executable not found. 1>&2 + ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 + EXIT /B 1 +) + REM Test if the flutter directory is a git clone, otherwise git rev-parse HEAD would fail IF NOT EXIST "%flutter_root%\.git" ( ECHO Error: The Flutter directory is not a clone of the GitHub project. diff --git a/bin/flutter.bat b/bin/flutter.bat index 59df026a7f19d..f9cc9ec8622b4 100644 --- a/bin/flutter.bat +++ b/bin/flutter.bat @@ -22,7 +22,26 @@ REM If available, add location of bundled mingit to PATH SET mingit_path=%FLUTTER_ROOT%\bin\mingit\cmd IF EXIST "%mingit_path%" SET PATH=%PATH%;%mingit_path% -REM We test if Git is available on the Host as we run git in shared.bat +REM Test if Git is available on the host +WHERE /Q git +IF "%ERRORLEVEL%" NEQ "0" ( + ECHO Error: Unable to find git in your PATH. + EXIT /B 1 +) + +REM Detect which PowerShell executable is available on the host +REM PowerShell version <= 5: PowerShell.exe +REM PowerShell version >= 6: pwsh.exe +WHERE /Q pwsh.exe && ( + SET powershell_executable=pwsh.exe +) || WHERE /Q PowerShell.exe && ( + SET powershell_executable=PowerShell.exe +) || ( + ECHO Error: PowerShell executable not found. 1>&2 + ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 + EXIT /B 1 +) + REM Test if the flutter directory is a git clone, otherwise git rev-parse HEAD would fail IF NOT EXIST "%flutter_root%\.git" ( ECHO Error: The Flutter directory is not a clone of the GitHub project. diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 4ee2635073465..141b461793087 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -6eebe72ca3975373a5fab06a009ec5ffeabdb495 +ecba2dbf07ee4b96a0e16b9be5e62f16f6a4ec2c diff --git a/bin/internal/libimobiledevice.version b/bin/internal/libimobiledevice.version index 3efb10b51f8c8..5843f21b97d54 100644 --- a/bin/internal/libimobiledevice.version +++ b/bin/internal/libimobiledevice.version @@ -1 +1 @@ -2ba8188ed97d8b05670845e5b5954e2fe0f54784 +0bf0f9e941c85d06ce4b5909d7a61b3a4f2a6a05 diff --git a/bin/internal/libimobiledeviceglue.version b/bin/internal/libimobiledeviceglue.version new file mode 100644 index 0000000000000..82ffe9ae50f42 --- /dev/null +++ b/bin/internal/libimobiledeviceglue.version @@ -0,0 +1 @@ +050ff3bf8fdab6ce53a2ddc6ae49b11b1c02a168 diff --git a/bin/internal/libplist.version b/bin/internal/libplist.version index 8619a4b85a686..0f7e45becd3e7 100644 --- a/bin/internal/libplist.version +++ b/bin/internal/libplist.version @@ -1 +1 @@ -20a2f8dbddcf1a96ad4c720b9afd1d0876d17ffc +cf5897a71ea412ea2aeb1e2f6b5ea74d4fabfd8c diff --git a/bin/internal/libusbmuxd.version b/bin/internal/libusbmuxd.version new file mode 100644 index 0000000000000..7bb041038491c --- /dev/null +++ b/bin/internal/libusbmuxd.version @@ -0,0 +1 @@ +19d6bec393c9f9b31ccb090059f59268da32e281 diff --git a/bin/internal/openssl.version b/bin/internal/openssl.version index 6d2eb55065c53..97f63170a3e7d 100644 --- a/bin/internal/openssl.version +++ b/bin/internal/openssl.version @@ -1 +1 @@ -e2e09d9fba1187f8d6aafaa34d4172f56f1ffb72 +22dbb176deef7d9a80f5c94f57a4b518ea935f50 diff --git a/bin/internal/shared.bat b/bin/internal/shared.bat index f9a7a0474c8df..85455e426e86a 100644 --- a/bin/internal/shared.bat +++ b/bin/internal/shared.bat @@ -52,12 +52,7 @@ GOTO :after_subroutine CALL "%bootstrap_path%" ) - REM Check that git exists and get the revision. - WHERE git >NUL 2>&1 - IF "%ERRORLEVEL%" NEQ "0" ( - REM Could not find git. Exit without /B to avoid retrying. - ECHO Error: Unable to find git in your PATH. && EXIT 1 - ) + REM Get the Git revision. 2>NUL ( REM 'FOR /f' spawns a new terminal instance to run the command. If an REM 'AutoRun' command is defined in the user's registry, that command could @@ -103,18 +98,6 @@ GOTO :after_subroutine EXIT /B :do_ensure_engine_version - REM Detect which PowerShell executable is available on the Host - REM PowerShell version <= 5: PowerShell.exe - REM PowerShell version >= 6: pwsh.exe - WHERE /Q pwsh.exe && ( - SET powershell_executable=pwsh.exe - ) || WHERE /Q PowerShell.exe && ( - SET powershell_executable=PowerShell.exe - ) || ( - ECHO Error: PowerShell executable not found. 1>&2 - ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 - EXIT 1 - ) SET update_engine_bin=%FLUTTER_ROOT%\bin\internal\update_engine_version.ps1 REM Escape apostrophes from the executable path SET "update_engine_bin=%update_engine_bin:'=''%" @@ -133,18 +116,6 @@ GOTO :after_subroutine EXIT /B :do_sdk_update_and_snapshot - REM Detect which PowerShell executable is available on the Host - REM PowerShell version <= 5: PowerShell.exe - REM PowerShell version >= 6: pwsh.exe - WHERE /Q pwsh.exe && ( - SET powershell_executable=pwsh.exe - ) || WHERE /Q PowerShell.exe && ( - SET powershell_executable=PowerShell.exe - ) || ( - ECHO Error: PowerShell executable not found. 1>&2 - ECHO Either pwsh.exe or PowerShell.exe must be in your PATH. 1>&2 - EXIT 1 - ) SET /A dart_sdk_retries+=1 ECHO Checking Dart SDK version... 1>&2 SET update_dart_bin=%FLUTTER_ROOT%\bin\internal\update_dart_sdk.ps1 diff --git a/bin/internal/usbmuxd.version b/bin/internal/usbmuxd.version deleted file mode 100644 index 66ab87775f3b7..0000000000000 --- a/bin/internal/usbmuxd.version +++ /dev/null @@ -1 +0,0 @@ -c7d7d1a03f65a27be2eddb13d1f2b0c0e7a60ec6 diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index 57c2fabf79d40..05fd6f0e9f22d 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -5,38 +5,20 @@ version: 5.0.0+5 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + material_color_utilities: any dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: aopqns diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 4de15bb766baa..04251efc60c18 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -3,6 +3,8 @@ name: flutter_automated_tests environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -12,69 +14,14 @@ dependencies: sdk: flutter integration_test: sdk: flutter - platform: 3.1.6 - test: 1.26.1 + platform: any + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: any flutter: uses-material-design: true assets: - icon/test.png -# PUBSPEC CHECKSUM: d92e +# PUBSPEC CHECKSUM: 1nm9kf diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 5a93962ea7e8c..be8deaa2d5a27 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -4,6 +4,8 @@ description: A benchmark of a relatively complex layout. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -14,73 +16,17 @@ dependencies: # //packages/flutter_tools/lib/src/commands/update_packages.dart # and run # flutter update-packages --force-upgrade - flutter_gallery_assets: 1.0.2 + flutter_gallery_assets: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any integration_test: sdk: flutter - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -88,4 +34,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: o8fml4 diff --git a/dev/benchmarks/imitation_game_flutter/.gitignore b/dev/benchmarks/imitation_game_flutter/.gitignore index 747c233ea24c3..a3dd4973f338b 100644 --- a/dev/benchmarks/imitation_game_flutter/.gitignore +++ b/dev/benchmarks/imitation_game_flutter/.gitignore @@ -27,7 +27,6 @@ migrate_working_dir/ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .pub-cache/ .pub/ diff --git a/dev/benchmarks/imitation_game_flutter/pubspec.yaml b/dev/benchmarks/imitation_game_flutter/pubspec.yaml index 171ad5feeb79f..aa2431b6d0175 100644 --- a/dev/benchmarks/imitation_game_flutter/pubspec.yaml +++ b/dev/benchmarks/imitation_game_flutter/pubspec.yaml @@ -6,42 +6,20 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-208.0.dev +resolution: workspace + dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.8 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - flutter_lints: 5.0.0 - - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - lints: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d34d +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/material3.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/material3.dart index 2e516d18309c3..02db61263d880 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/material3.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/material3.dart @@ -870,7 +870,6 @@ class _RadiosState extends State { title: const Text('Option 3'), value: Options.option3, groupValue: _selectedOption, - onChanged: null, ), ], ), diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 0ed004ef36151..0346de02a1eaa 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -4,6 +4,8 @@ description: Performance benchmarks using flutter drive. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -16,72 +18,17 @@ dependencies: # //packages/flutter_tools/lib/src/commands/update_packages.dart # and run # flutter update-packages --force-upgrade - flutter_gallery_assets: 1.0.2 - - args: 2.7.0 - web: 1.1.1 + flutter_gallery_assets: any + args: any + web: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: any dev_dependencies: - test: 1.26.1 + test: any integration_test: sdk: flutter - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -215,4 +162,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: fh1ejq diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index c5bce68f75dcd..87a12c173cbe7 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -4,74 +4,17 @@ description: Small benchmarks for very specific parts of the Flutter framework. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - meta: 1.16.0 flutter: sdk: flutter flutter_test: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.26.1 - flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - intl: 0.20.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - isolate: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + args: any flutter: uses-material-design: true @@ -142,4 +85,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 873f +# PUBSPEC CHECKSUM: vrfq3l diff --git a/dev/benchmarks/multiple_flutters/module/.gitignore b/dev/benchmarks/multiple_flutters/module/.gitignore index ff612b3be434c..8cb6ed8be8fe3 100644 --- a/dev/benchmarks/multiple_flutters/module/.gitignore +++ b/dev/benchmarks/multiple_flutters/module/.gitignore @@ -38,7 +38,6 @@ Icon? build/ .android/ .ios/ -.flutter-plugins .flutter-plugins-dependencies # Symbolication related diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 480fa64302af8..e04dab5e8906e 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -6,38 +6,14 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.8 - google_fonts: 6.2.1 - - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.2.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + google_fonts: any + flutter: uses-material-design: true @@ -47,4 +23,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 0c7c +# PUBSPEC CHECKSUM: 4htetl diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index fec08c96a8155..3b994d9d08157 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -7,6 +7,8 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -14,69 +16,11 @@ dependencies: sdk: flutter microbenchmarks: path: ../microbenchmarks - cupertino_icons: 1.0.8 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # 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: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d68 +# PUBSPEC CHECKSUM: vblobb diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 77c5d121d2d6b..9f25795afcf7a 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -4,86 +4,25 @@ description: A benchmark for platform views. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - google_mobile_ads: 5.1.0 + google_mobile_ads: any # To change the version of the gallery assets, edit # //packages/flutter_tools/lib/src/commands/update_packages.dart # and run # flutter update-packages --force-upgrade - flutter_gallery_assets: 1.0.2 - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webview_flutter: 4.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webview_flutter_android: 3.16.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webview_flutter_platform_interface: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webview_flutter_wkwebview: 3.22.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -91,4 +30,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: f9ca +# PUBSPEC CHECKSUM: a4ttir diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 33288ce9b305e..c97179ce0cddd 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -4,6 +4,8 @@ description: A benchmark for platform views, using hybrid composition on android environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -14,71 +16,13 @@ dependencies: # //packages/flutter_tools/lib/src/commands/update_packages.dart # and run # flutter update-packages --force-upgrade - flutter_gallery_assets: 1.0.2 - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -86,4 +30,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: dgjojg diff --git a/dev/benchmarks/test_apps/stocks/l10n.yaml b/dev/benchmarks/test_apps/stocks/l10n.yaml index 414eb5f7f61ac..07c0ff53b1dd2 100644 --- a/dev/benchmarks/test_apps/stocks/l10n.yaml +++ b/dev/benchmarks/test_apps/stocks/l10n.yaml @@ -14,7 +14,6 @@ output-localization-file: stock_strings.dart ## `template-arb-file` describes the template arb file that the tool ## will use to check and validate the remaining arb files when ## generating Flutter's localization files. -synthetic-package: false template-arb-file: stocks_en.arb ## setting `nullable-getter` to false generates a non-nullable ## StockStrings getter. This removes the need for adding null checks diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 85913a00c595f..5b4db8ca5cd81 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -3,83 +3,27 @@ name: stocks environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter - intl: 0.20.2 - http: 1.4.0 - isolate: 2.1.1 + intl: any + http: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # 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.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: generate: true uses-material-design: true -# PUBSPEC CHECKSUM: 07e8 +# PUBSPEC CHECKSUM: 69qefu diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 38703a7a36637..dd9e2403ae665 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -95,6 +95,9 @@ Future run(List arguments) async { foundError(['The analyze.dart script must be run with --enable-asserts.']); } + printProgress('Release branch validation'); + await verifyReleaseBranchState(flutterRoot); + printProgress('TargetPlatform tool/framework consistency'); await verifyTargetPlatform(flutterRoot); @@ -172,10 +175,7 @@ Future run(List arguments) async { // Ensure that all package dependencies are in sync. printProgress('Package dependencies...'); - await runCommand(flutter, [ - 'update-packages', - '--verify-only', - ], workingDirectory: flutterRoot); + await runCommand(flutter, ['update-packages'], workingDirectory: flutterRoot); /// Ensure that no new dependencies have been accidentally /// added to core packages. @@ -303,6 +303,15 @@ _Line _getLine(ParseStringResult parseResult, int offset) { return _Line(lineNumber, content); } +Future verifyReleaseBranchState(String workringDirerctory) async { + final ProcessResult result = await Process.run(dart, [ + 'bin/check_engine_version.dart', + ], workingDirectory: path.join(workringDirerctory, 'dev', 'tools')); + if (result.exitCode != 0) { + foundError(['${result.stderr}']); + } +} + Future verifyTargetPlatform(String workingDirectory) async { final File framework = File( '$workingDirectory/packages/flutter/lib/src/foundation/platform.dart', @@ -2336,7 +2345,7 @@ Future _checkConsumerDependencies() async { dependencies.add(currentPackage['name']! as String); final List currentDependencies = - (currentPackage['dependencies']! as List).cast(); + (currentPackage['directDependencies']! as List).cast(); for (final String dependency in currentDependencies) { // Don't add dependencies we've already seen or we will get stuck // forever if there are any circular references. diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index af8b186144621..28cb38dd6695d 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -75,6 +75,9 @@ import 'package:args/args.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'package:watcher/watcher.dart'; +import 'package:yaml_edit/yaml_edit.dart' show YamlEditor; + +const String _pubspecName = 'pubspec.yaml'; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); @@ -175,7 +178,7 @@ Future main(List arguments) async { if (entity is! Directory) { continue; } - final File pubspec = File(path.join(entity.path, 'pubspec.yaml')); + final File pubspec = File(path.join(entity.path, _pubspecName)); if (!pubspec.existsSync()) { throw StateError("Unexpected package '${entity.path}' found in packages directory"); } @@ -472,6 +475,14 @@ class _SnippetChecker { /// automatically if there are no errors unless _keepTmp is true. final Directory _tempDirectory; + Directory get _contentDirectory { + final Directory directory = Directory(path.join(_tempDirectory.path, 'packages')); + if (!directory.existsSync()) { + directory.createSync(); + } + return directory; + } + /// The package directories within the flutter root dir that will be checked. final List _flutterPackages; @@ -982,17 +993,21 @@ class _SnippetChecker { /// Creates the configuration files necessary for the analyzer to consider /// the temporary directory a package, and sets which lint rules to enforce. void _createConfigurationFiles() { - final File targetPubSpec = File(path.join(_tempDirectory.path, 'pubspec.yaml')); - if (!targetPubSpec.existsSync()) { - // Copying pubspec.yaml from examples/api into temp directory. - final File sourcePubSpec = File(path.join(_flutterRoot, 'examples', 'api', 'pubspec.yaml')); - if (!sourcePubSpec.existsSync()) { - throw 'Cannot find pubspec.yaml at ${sourcePubSpec.path}, which is also used to analyze code snippets.'; - } - sourcePubSpec.copySync(targetPubSpec.path); - } + final String targetWorkspacePubspecPath = path.join(_tempDirectory.path, _pubspecName); + _copyPubspec(targetWorkspacePubspecPath, path.join(_flutterRoot, _pubspecName)); + final File targetWorkspacePubspec = File(targetWorkspacePubspecPath); + final String pubspec = targetWorkspacePubspec.readAsStringSync(); + + final YamlEditor yamlEditor = YamlEditor(pubspec); + yamlEditor.update(['workspace'], ['packages']); + targetWorkspacePubspec.writeAsStringSync(yamlEditor.toString()); + + _copyPubspec( + path.join(_contentDirectory.path, _pubspecName), + path.join(_flutterRoot, 'examples', 'api', _pubspecName), + ); final File targetAnalysisOptions = File( - path.join(_tempDirectory.path, 'analysis_options.yaml'), + path.join(_contentDirectory.path, 'analysis_options.yaml'), ); if (!targetAnalysisOptions.existsSync()) { // Use the same analysis_options.yaml configuration that's used for examples/api. @@ -1008,6 +1023,20 @@ class _SnippetChecker { } } + void _copyPubspec(String targetPath, String sourcePath) { + final File targetPubSpec = File(targetPath); + if (!targetPubSpec.existsSync()) { + // Copying pubspec.yaml from examples/api into temp directory. + final File sourcePubSpec = File(sourcePath); + if (!sourcePubSpec.existsSync()) { + throw 'Cannot find pubspec.yaml at ${sourcePubSpec.path}, which is also used to analyze code snippets.'; + } + targetPubSpec + ..createSync(recursive: true) + ..writeAsStringSync(sourcePubSpec.readAsStringSync()); + } + } + /// Writes out a snippet section to the disk and returns the file. File _writeSnippetFile(_SnippetFile snippetFile) { final String snippetFileId = _createNameFromSource( @@ -1015,7 +1044,7 @@ class _SnippetChecker { snippetFile.filename, snippetFile.indexLine, ); - final File outputFile = File(path.join(_tempDirectory.path, '$snippetFileId.dart')) + final File outputFile = File(path.join(_contentDirectory.path, '$snippetFileId.dart')) ..createSync(recursive: true); final String contents = snippetFile.code.map((_Line line) => line.code).join('\n').trimRight(); @@ -1045,7 +1074,7 @@ class _SnippetChecker { continue; } final String message = match.namedGroup('description')!; - final File file = File(path.join(_tempDirectory.path, match.namedGroup('file'))); + final File file = File(path.join(_contentDirectory.path, match.namedGroup('file'))); final List fileContents = file.readAsLinesSync(); final String lineString = match.namedGroup('line')!; final String columnString = match.namedGroup('column')!; @@ -1146,14 +1175,13 @@ class _SnippetChecker { Process.runSync(_flutter, [ 'pub', 'get', - ], workingDirectory: _tempDirectory.absolute.path); + ], workingDirectory: _contentDirectory.absolute.path); final ProcessResult result = Process.runSync(_flutter, [ '--no-wrap', 'analyze', - '--no-preamble', '--no-congratulate', '.', - ], workingDirectory: _tempDirectory.absolute.path); + ], workingDirectory: _contentDirectory.absolute.path); final List stderr = result.stderr.toString().trim().split('\n'); final List stdout = result.stdout.toString().trim().split('\n'); // Remove output from building the flutter tool. @@ -1172,13 +1200,12 @@ class _SnippetChecker { if (stderr.isNotEmpty && stderr.any((String line) => line.isNotEmpty)) { throw _SnippetCheckerException('Cannot analyze dartdocs; unexpected error output:\n$stderr'); } - if (stdout.isNotEmpty && stdout.first == 'Building flutter tool...') { - stdout.removeAt(0); - } - if (stdout.isNotEmpty && stdout.first.isEmpty) { - stdout.removeAt(0); - } - return stdout; + // Skip the boring part of the analysis, the preface - we only want the errors. + return stdout + .skipWhile((String line) => !line.startsWith('Analyzing packages...')) + .skip(1) + .skipWhile((String line) => line.isEmpty) + .toList(); } } diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 3c375ed52ba53..a57a4ae00c2d5 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -4,78 +4,34 @@ description: Scripts which run on bots. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - analyzer: 7.4.5 - args: 2.7.0 - crypto: 3.0.6 - intl: 0.20.2 - file: 7.0.1 + analyzer: any + args: any + crypto: any + intl: any + file: any flutter_devicelab: path: ../devicelab - http_parser: 4.1.2 - meta: 1.16.0 - path: 1.9.1 - platform: 3.1.6 - process: 5.0.3 - test: 1.26.1 + meta: any + path: any + platform: any + process: any + test: any - _discoveryapis_commons: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - archive: 3.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.18 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - google_identity_services_web: 0.3.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis: 12.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis_auth: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 6.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pubspec_parse: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - standard_message_codec: 0.0.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xml: 6.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: any + collection: any + convert: any + glob: any + http: any + pool: any + shelf: any + shelf_static: any + source_span: any + watcher: any + yaml: any + yaml_edit: any -dev_dependencies: - test_api: 0.7.6 -# PUBSPEC CHECKSUM: df1a +# PUBSPEC CHECKSUM: 8lua9g diff --git a/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart b/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart index 067b93efc9295..aae0de1e9dc7b 100644 --- a/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart +++ b/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart @@ -62,11 +62,12 @@ List binariesWithEntitlements(String flutterRoot) { 'artifacts/libimobiledevice/idevicescreenshot', 'artifacts/libimobiledevice/idevicesyslog', 'artifacts/libimobiledevice/libimobiledevice-1.0.6.dylib', - 'artifacts/libplist/libplist-2.0.3.dylib', - 'artifacts/openssl/libcrypto.1.1.dylib', - 'artifacts/openssl/libssl.1.1.dylib', - 'artifacts/usbmuxd/iproxy', - 'artifacts/usbmuxd/libusbmuxd-2.0.6.dylib', + 'artifacts/libimobiledeviceglue/libimobiledevice-glue-1.0.0.dylib', + 'artifacts/libplist/libplist-2.0.4.dylib', + 'artifacts/openssl/libcrypto.3.dylib', + 'artifacts/openssl/libssl.3.dylib', + 'artifacts/libusbmuxd/iproxy', + 'artifacts/libusbmuxd/libusbmuxd-2.0.7.dylib', 'dart-sdk/bin/dart', 'dart-sdk/bin/dartaotruntime', 'dart-sdk/bin/utils/gen_snapshot', diff --git a/dev/bots/suite_runners/run_web_tests.dart b/dev/bots/suite_runners/run_web_tests.dart index 58101f023bef7..6b56ceeca9a76 100644 --- a/dev/bots/suite_runners/run_web_tests.dart +++ b/dev/bots/suite_runners/run_web_tests.dart @@ -360,6 +360,8 @@ class WebTestsSuite { '--browser-name=chrome', '-d', 'web-server', + // TODO(nshahan): Remove when web-server can run with hot reload, https://github.com/dart-lang/sdk/issues/60289. + if (buildMode == 'debug') '--no-web-experimental-hot-reload', '--$buildMode', if (webRenderer == 'skwasm') ...[ // See: WebRendererMode.dartDefines[skwasm] @@ -487,6 +489,7 @@ class WebTestsSuite { '--browser-name=chrome', '-d', 'web-server', + if (buildMode == 'debug') '--no-web-experimental-hot-reload', '--$buildMode', ], workingDirectory: testAppDirectory, diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 42f8253b87510..8303a5ab13ae4 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -295,7 +295,7 @@ Future runForbiddenFromReleaseTests() async { '--snapshot', path.join(tempDirectory.path, 'snapshot.arm64-v8a.json'), '--package-config', - path.join(flutterRoot, 'examples', 'hello_world', '.dart_tool', 'package_config.json'), + path.join(flutterRoot, '.dart_tool', 'package_config.json'), '--forbidden-type', 'package:flutter/src/widgets/framework.dart::Widget', ]; @@ -307,7 +307,7 @@ Future runForbiddenFromReleaseTests() async { '--snapshot', path.join(tempDirectory.path, 'snapshot.arm64-v8a.json'), '--package-config', - path.join(flutterRoot, 'examples', 'hello_world', '.dart_tool', 'package_config.json'), + path.join(flutterRoot, '.dart_tool', 'package_config.json'), '--forbidden-type', 'package:flutter/src/widgets/widget_inspector.dart::WidgetInspectorService', '--forbidden-type', diff --git a/dev/bots/utils.dart b/dev/bots/utils.dart index 45033ca39886e..75d66f70344dd 100644 --- a/dev/bots/utils.dart +++ b/dev/bots/utils.dart @@ -107,9 +107,17 @@ const int kCSIIntermediateRangeEnd = 0x2F; const int kCSIFinalRangeStart = 0x40; const int kCSIFinalRangeEnd = 0x7E; +int get terminalColumns { + try { + return stdout.terminalColumns; + } catch (e) { + return 40; + } +} + String get redLine { if (hasColor) { - return '$red${'━' * stdout.terminalColumns}$reset'; + return '$red${'━' * terminalColumns}$reset'; } return '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; } @@ -168,7 +176,7 @@ void foundError(List messages) { assert(messages.isNotEmpty); // Make the error message easy to notice in the logs by // wrapping it in a red box. - final int width = math.max(15, (hasColor ? stdout.terminalColumns : 80) - 1); + final int width = math.max(15, (hasColor ? terminalColumns : 80) - 1); final String title = 'ERROR #${_errorMessages.length + 1}'; print('$red╔═╡$bold$title$reset$red╞═${"═" * (width - 4 - title.length)}'); for (final String message in messages.expand((String line) => line.split('\n'))) { @@ -258,7 +266,7 @@ void _printQuietly(Object? message) { final int start = line.lastIndexOf(_lineBreak) + 1; int index = start; int length = 0; - while (index < line.length && length < stdout.terminalColumns) { + while (index < line.length && length < terminalColumns) { if (line.codeUnitAt(index) == kESC) { // 0x1B index += 1; diff --git a/dev/conductor/README.md b/dev/conductor/README.md index d406d7f140b33..de49d3e87f209 100644 --- a/dev/conductor/README.md +++ b/dev/conductor/README.md @@ -1,102 +1,8 @@ # Flutter Conductor -Command-line tool for managing a release of the Flutter SDK. Also see -[Release Process](../../docs/releases/Release-process.md) for more information on -the release process. +This directory contains the skeletal remains of the `conductor` tool, which was +used to semi-automate releases. It still has a functional tool +(`packages_autoroller`) which is in the process of being moved to a dedicated +directory. -## Conductor Requirements - -Some basic requirements to run conductor are: - -- a Linux or macOS computer set up for Flutter development. The conductor does - not support Windows. -- git -- Mirrors on GitHub of the Flutter ** - [framework](https://github.com/flutter/flutter) and - [engine](https://github.com/flutter/engine) repositories. - -For the best experience, it is recommended to use ssh protocol for connecting to -GitHub remote repositories (i.e. for `--framework-mirror` and `--engine-mirror` -specify the remote with the format `git@github.com:username/reponame`). If your -local ssh key is password-protected, it is recommended to use ssh-agent to -unlock your ssh key for the session; if you do not, each time the conductor -attempts to interact with a remote, the user will be prompted to enter their ssh -key password. - -** Confirm that your personal GitHub clone of flutter/flutter is named flutter and flutter/engine is named engine. If not you will need to use flags to override the defaults. - -## Usage - -The main entrypoint for the conductor is [bin/conductor](bin/conductor). For -brevity, the rest of this document will assume that this entrypoint is on the -shell path. - -All available commands can be seen via: - -`conductor help` - -Releases are initialized with the `start` sub-command, like: - -```sh -conductor start \ - --candidate-branch=flutter-2.2-candidate.10 \ - --release-channel=beta \ - --github-username=kingOfDevelopers \ - --dart-revision=4511eb2a779a612d9d6b2012123575013e0aef12 \ -``` - -The conductor will, based on the release channel and the presence/lack of -previous tags, determine which part of the release version should be -incremented. In the cases where this is not correct, the version can be -overridden with `--version-override=3.0.0`. - -For more details on these command line arguments, see `conductor help start`. -This command will write to disk a state file that will persist until the release -is completed. If you already have a persistent state file, this command will -fail with an error message. To see the current status of the release (at any -time), issue the command: - -`conductor status` - -To delete a persistent state file (either because the release was successfully -completed or abandoned), use the command: - -`conductor clean` - -Once initializing the release, the conductor tool will issue instructions for -manual steps that must be executed by the user. At any time these instructions -can be seen via `conductor status`. Once these manual steps have been completed, -you can proceed to the next step by using the command: - -`conductor next` - -## Steps - -Once the user has finished manual steps for each step, they proceed to the next -step with the command: - -`conductor next` - -### Publish Version - -This step will add a version git tag to the final Framework commit and push it -to the upstream repository. The presence of a tag affects what the flutter CLI -tool reports the current version is. - -### Publish Channel - -This step will push the Framework candidate branch to the upstream release -branch (e.g. the `stable` branch). Once this push happens upstream, the release -has officially been published, and the code will be available to existing -Flutter users via `flutter upgrade`. - -### Verify Release - -For the final step, the user must manually verify that packaging builds have -finished successfully. The SDK compressed archives will not be available from -the website until the packaging build has finished. The conductor will produce -links to the dashboards for monitoring CI builds. - -### Post verificaion steps (mostly communication) - -Googler instructions for post release documented at go/flutter-release-workflow#notify +Questions? Ask @matanlurey. diff --git a/dev/conductor/RELEASE_ONBOARDING.md b/dev/conductor/RELEASE_ONBOARDING.md deleted file mode 100644 index 9253bc33513cf..0000000000000 --- a/dev/conductor/RELEASE_ONBOARDING.md +++ /dev/null @@ -1,71 +0,0 @@ -# Release engineer/manager onboarding - -Googler facing documentation can be found at go/flutter-release-workflow. - -### Responsibility - -Release engineer is responsible for: -* Branch alignment and/or shepherding cherry picks -* Decision making related to cherry pick risk -* Verification that pre and post submits pass prior to publishing -* Contributor facing communication -* Some public facing post release communication - -In the past (and possibly in the future) there was a distinction between a release engineer and release manager. -For now the responsibilities are the same and we will refer to the person managing the release as a release engineer. - -## Onboarding - -One time setup instructions for new or returning release engineers. - -### Groups/Permissions - -#### Join flutter-hackers on GitHub - -https://github.com/orgs/flutter/teams/flutter-hackers/members - -#### [Googler only] Join mdb/flutter-infra - -Possibly not required -https://ganpati2.corp.google.com/propose_membership?parent=9147533327&child=$me.prod - -#### Join the flutter-announce google group - -Ping any current release engineer to add you as an owner and give you publish access. -https://groups.google.com/g/flutter-announce/members?q=role:owner&pli=1 - -TODO include screenshot - -#### [Googler only] Install tool-proxy-client - -From a glinux machine run `sudo apt install tool-proxy-client`. - -`tool-proxy-client` is the tool that enables/enforces 2 party authorization for controlled builds. - -#### [Googler only] Confirm access to release calendar - -Public and Beta releases and timelines -go/dash-team-releases - -#### [Googler only] Join release chatroom - -Release hotline https://chat.google.com/room/AAAA6RKcK2k?cls=7 - -#### [Googler only] join mdb/flutter-release-team - -Controls who can approve 2 party auth requests. -https://ganpati2.corp.google.com/propose_membership?parent=100213927583&child=$me.prod - -#### Setup conductor - -Conductor is a dart command line interface for common release tasks. -Its instructions are in README.md. - -#### [Googler only] Confirm access to Apple signing cert update doc - -go/flutter-signing-apple-contracts -Also confirm access to valentine entries listed in that doc. - -#### [Googler only] Access release engineer doc - -Confirm access to go/release-eng-retros diff --git a/dev/conductor/bin/packages_autoroller b/dev/conductor/bin/packages_autoroller index c424296009128..d81a354727a4b 100755 --- a/dev/conductor/bin/packages_autoroller +++ b/dev/conductor/bin/packages_autoroller @@ -39,8 +39,9 @@ PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")" BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" REPO_DIR="$BIN_DIR/../../.." DART_BIN="$REPO_DIR/bin/dart" +FLUTTER_BIN="$REPO_DIR/bin/flutter" # Ensure pub get has been run in the repo before running the conductor -(cd "$REPO_DIR/dev/conductor/core"; "$DART_BIN" pub get 1>&2) +(cd "$REPO_DIR/dev/conductor/core"; "$FLUTTER_BIN" pub get 1>&2) exec "$DART_BIN" --enable-asserts "$REPO_DIR/dev/conductor/core/bin/packages_autoroller.dart" "$@" diff --git a/dev/conductor/core/bin/cli.dart b/dev/conductor/core/bin/cli.dart deleted file mode 100644 index 121a9d8970602..0000000000000 --- a/dev/conductor/core/bin/cli.dart +++ /dev/null @@ -1,82 +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. - -// See: https://github.com/flutter/flutter/blob/main/docs/releases/Release-process.md - -import 'dart:io' as io; - -import 'package:args/command_runner.dart'; -import 'package:conductor_core/conductor_core.dart'; -import 'package:file/file.dart'; -import 'package:file/local.dart'; -import 'package:platform/platform.dart'; -import 'package:process/process.dart'; - -const String readmeUrl = 'https://github.com/flutter/flutter/tree/main/dev/conductor/README.md'; - -Future main(List args) async { - const FileSystem fileSystem = LocalFileSystem(); - const ProcessManager processManager = LocalProcessManager(); - const Platform platform = LocalPlatform(); - final Stdio stdio = VerboseStdio(stdout: io.stdout, stderr: io.stderr, stdin: io.stdin); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: _localFlutterRoot.parent, - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final CommandRunner runner = CommandRunner( - 'conductor', - 'A tool for coordinating Flutter releases. For more documentation on ' - 'usage, please see $readmeUrl.', - usageLineLength: 80, - ); - - final String conductorVersion = - (await const Git(processManager).getOutput( - ['rev-parse'], - 'Get the revision of the current Flutter SDK', - workingDirectory: _localFlutterRoot.path, - )).trim(); - - >[ - StatusCommand(checkouts: checkouts), - StartCommand(checkouts: checkouts, conductorVersion: conductorVersion), - CleanCommand(checkouts: checkouts), - CandidatesCommand(checkouts: checkouts, flutterRoot: _localFlutterRoot), - NextCommand(checkouts: checkouts), - ].forEach(runner.addCommand); - - if (!assertsEnabled()) { - stdio.printError('The conductor tool must be run with --enable-asserts.'); - io.exit(1); - } - - try { - await runner.run(args); - } on Exception catch (e, stacktrace) { - stdio.printError('$e\n\n$stacktrace'); - io.exit(1); - } -} - -Directory get _localFlutterRoot { - String filePath; - const FileSystem fileSystem = LocalFileSystem(); - const Platform platform = LocalPlatform(); - - filePath = platform.script.toFilePath(); - final String checkoutsDirname = fileSystem.path.normalize( - fileSystem.path.join( - fileSystem.path.dirname(filePath), // flutter/dev/conductor/core/bin - '..', // flutter/dev/conductor/core - '..', // flutter/dev/conductor - '..', // flutter/dev - '..', // flutter - ), - ); - return fileSystem.directory(checkoutsDirname); -} diff --git a/dev/conductor/core/bin/packages_autoroller.dart b/dev/conductor/core/bin/packages_autoroller.dart index 393adc8e1ef00..9a0b4f8535ccc 100644 --- a/dev/conductor/core/bin/packages_autoroller.dart +++ b/dev/conductor/core/bin/packages_autoroller.dart @@ -5,8 +5,9 @@ import 'dart:io' as io; import 'package:args/args.dart'; -import 'package:conductor_core/conductor_core.dart'; import 'package:conductor_core/packages_autoroller.dart'; +import 'package:conductor_core/src/repository.dart'; +import 'package:conductor_core/src/stdio.dart'; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:meta/meta.dart' show visibleForTesting; diff --git a/dev/conductor/core/lib/conductor_core.dart b/dev/conductor/core/lib/conductor_core.dart deleted file mode 100644 index 6b34f9fc95815..0000000000000 --- a/dev/conductor/core/lib/conductor_core.dart +++ /dev/null @@ -1,16 +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. - -// See: https://github.com/flutter/flutter/blob/main/docs/releases/Release-process.md - -export 'src/candidates.dart'; -export 'src/clean.dart'; -export 'src/git.dart'; -export 'src/globals.dart'; -export 'src/next.dart' hide kStateOption, kYesFlag; -export 'src/repository.dart'; -export 'src/start.dart' hide kStateOption; -export 'src/state.dart'; -export 'src/status.dart' hide kStateOption; -export 'src/stdio.dart'; diff --git a/dev/conductor/core/lib/src/candidates.dart b/dev/conductor/core/lib/src/candidates.dart deleted file mode 100644 index 536c452b06337..0000000000000 --- a/dev/conductor/core/lib/src/candidates.dart +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/args.dart'; -import 'package:args/command_runner.dart'; -import 'package:file/file.dart'; - -import './git.dart'; -import './globals.dart' show releaseCandidateBranchRegex; -import './repository.dart'; -import './stdio.dart'; -import './version.dart'; - -const String kRemote = 'remote'; - -class CandidatesCommand extends Command { - CandidatesCommand({required this.flutterRoot, required this.checkouts}) - : git = Git(checkouts.processManager), - stdio = checkouts.stdio { - argParser.addOption( - kRemote, - help: 'Which remote name to query for branches.', - defaultsTo: 'upstream', - ); - } - - final Checkouts checkouts; - final Directory flutterRoot; - final Git git; - final Stdio stdio; - - @override - String get name => 'candidates'; - - @override - String get description => 'List release candidates.'; - - @override - Future run() async { - final ArgResults results = argResults!; - await git.run( - ['fetch', results[kRemote] as String], - 'Fetch from remote ${results[kRemote]}', - workingDirectory: flutterRoot.path, - ); - - final FrameworkRepository framework = HostFrameworkRepository( - checkouts: checkouts, - name: 'framework-for-candidates', - upstreamPath: flutterRoot.path, - ); - - final Version currentVersion = await framework.flutterVersion(); - stdio.printStatus('currentVersion = $currentVersion'); - - final List branches = (await git.getOutput( - ['branch', '--no-color', '--remotes', '--list', '${results[kRemote]}/*'], - 'List all remote branches', - workingDirectory: flutterRoot.path, - )).split('\n'); - - // Pattern for extracting only the branch name via sub-group 1 - final RegExp remotePattern = RegExp('${results[kRemote]}\\/(.*)'); - for (final String branchName in branches) { - final RegExpMatch? candidateMatch = releaseCandidateBranchRegex.firstMatch(branchName); - if (candidateMatch == null) { - continue; - } - final int currentX = currentVersion.x; - final int currentY = currentVersion.y; - final int currentZ = currentVersion.z; - final int currentM = currentVersion.m ?? 0; - final int x = int.parse(candidateMatch.group(1)!); - final int y = int.parse(candidateMatch.group(2)!); - final int m = int.parse(candidateMatch.group(3)!); - - final RegExpMatch? match = remotePattern.firstMatch(branchName); - // If this is not the correct remote - if (match == null) { - continue; - } - if (x < currentVersion.x) { - continue; - } - if (x == currentVersion.x && y < currentVersion.y) { - continue; - } - if (x == currentX && y == currentY && currentZ == 0 && m <= currentM) { - continue; - } - stdio.printStatus(match.group(1)!); - } - } -} diff --git a/dev/conductor/core/lib/src/clean.dart b/dev/conductor/core/lib/src/clean.dart deleted file mode 100644 index 05d646cbc6ad2..0000000000000 --- a/dev/conductor/core/lib/src/clean.dart +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/args.dart'; -import 'package:args/command_runner.dart'; -import 'package:file/file.dart'; -import 'package:platform/platform.dart'; - -import './globals.dart'; -import './repository.dart'; -import './state.dart'; -import './stdio.dart'; - -const String kYesFlag = 'yes'; -const String kStateOption = 'state-file'; - -/// Command to clean up persistent state file. -/// -/// If the release was not completed, this command will abort the release. -class CleanCommand extends Command { - CleanCommand({required this.checkouts}) - : platform = checkouts.platform, - fileSystem = checkouts.fileSystem, - stdio = checkouts.stdio { - final String defaultPath = defaultStateFilePath(platform); - argParser.addFlag(kYesFlag, help: 'Override confirmation checks.'); - argParser.addOption( - kStateOption, - defaultsTo: defaultPath, - help: 'Path to persistent state file. Defaults to $defaultPath', - ); - } - - final Checkouts checkouts; - final FileSystem fileSystem; - final Platform platform; - final Stdio stdio; - - @override - String get name => 'clean'; - - @override - String get description => - 'Cleanup persistent state file. ' - 'This will abort a work in progress release.'; - - @override - Future run() { - final ArgResults argumentResults = argResults!; - final File stateFile = checkouts.fileSystem.file(argumentResults[kStateOption]); - if (!stateFile.existsSync()) { - throw ConductorException('No persistent state file found at ${stateFile.path}!'); - } - - if (!(argumentResults[kYesFlag] as bool)) { - stdio.printStatus( - 'Are you sure you want to clean up the persistent state file at\n' - '${stateFile.path} (y/n)?', - ); - final String response = stdio.readLineSync(); - - // Only proceed if the first character of stdin is 'y' or 'Y' - if (response.isEmpty || response[0].toLowerCase() != 'y') { - stdio.printStatus('Aborting clean operation.'); - } - } - stdio.printStatus('Deleting persistent state file ${stateFile.path}...'); - - final CleanContext cleanContext = CleanContext(stateFile: stateFile); - return cleanContext.run(); - } -} - -/// Context for cleaning up persistent state file. -/// -/// This is a frontend-agnostic implementation. -class CleanContext { - CleanContext({required this.stateFile}); - - final File stateFile; - - Future run() { - return stateFile.delete(); - } -} diff --git a/dev/conductor/core/lib/src/context.dart b/dev/conductor/core/lib/src/context.dart deleted file mode 100644 index 25132ddc7154b..0000000000000 --- a/dev/conductor/core/lib/src/context.dart +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file/file.dart' show File; - -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'repository.dart'; -import 'state.dart'; -import 'stdio.dart' show Stdio; - -/// Interface for shared functionality across all sub-commands. -/// -/// Different frontends (e.g. CLI vs desktop) can share [Context]s, although -/// methods for capturing user interaction may be overridden. -abstract class Context { - const Context({required this.checkouts, required this.stateFile}); - - final Checkouts checkouts; - final File stateFile; - Stdio get stdio => checkouts.stdio; - - /// Confirm an action with the user before proceeding. - /// - /// The default implementation reads from STDIN. This can be overridden in UI - /// implementations that capture user interaction differently. - Future prompt(String message) async { - stdio.write('${message.trim()} (y/n) '); - final String response = stdio.readLineSync().trim(); - final String firstChar = response[0].toUpperCase(); - if (firstChar == 'Y') { - return true; - } - if (firstChar == 'N') { - return false; - } - throw ConductorException('Unknown user input (expected "y" or "n"): $response'); - } - - /// Save the release's [state]. - /// - /// This can be overridden by frontends that may not persist the state to - /// disk, and/or may need to call additional update hooks each time the state - /// is updated. - void updateState(pb.ConductorState state, [List logs = const []]) { - writeStateToFile(stateFile, state, logs); - } -} diff --git a/dev/conductor/core/lib/src/globals.dart b/dev/conductor/core/lib/src/globals.dart index 84b226fceb3ff..79537be04fb84 100644 --- a/dev/conductor/core/lib/src/globals.dart +++ b/dev/conductor/core/lib/src/globals.dart @@ -4,7 +4,6 @@ import 'package:args/args.dart'; -import 'proto/conductor_state.pb.dart' as pb; import 'repository.dart'; const String gsutilBinary = 'gsutil.py'; @@ -137,64 +136,3 @@ List getValuesFromEnvOrArgs(String name, ArgResults argResults, Map (state.framework, 'Framework'), - 'engine' => (state.engine, 'Engine'), - _ => - throw ConductorException( - 'Expected repoName to be one of flutter or engine but got $repoName.', - ), - }; - final String candidateBranch = repository.candidateBranch; - final String workingBranch = repository.workingBranch; - assert(candidateBranch.isNotEmpty); - assert(workingBranch.isNotEmpty); - final String title = - '[flutter_releases] Flutter ${state.releaseChannel} ' - '${state.releaseVersion} $repoLabel Cherrypicks'; - final StringBuffer body = StringBuffer(); - body.write(''' -# Flutter ${state.releaseChannel} ${state.releaseVersion} $repoLabel - -## Scheduled Cherrypicks - -'''); - if (repoName == 'engine') { - if (state.engine.dartRevision.isNotEmpty) { - // shorten hashes to make final link manageable - // prefix with github org/repo so GitHub will auto-generate a hyperlink - body.writeln( - '- Roll dart revision: dart-lang/sdk@${state.engine.dartRevision.substring(0, 9)}', - ); - } - for (final pb.Cherrypick cp in state.engine.cherrypicks) { - // Only list commits that map to a commit that exists upstream. - if (cp.trunkRevision.isNotEmpty) { - body.writeln('- commit: flutter/engine@${cp.trunkRevision.substring(0, 9)}'); - } - } - } else { - for (final pb.Cherrypick cp in state.framework.cherrypicks) { - // Only list commits that map to a commit that exists upstream. - if (cp.trunkRevision.isNotEmpty) { - body.writeln('- commit: ${cp.trunkRevision.substring(0, 9)}'); - } - } - } - return 'https://github.com/flutter/$repoName/compare/' - '$candidateBranch...$userName:$workingBranch?' - 'expand=1' - '&title=${Uri.encodeQueryComponent(title)}' - '&body=${Uri.encodeQueryComponent(body.toString())}'; -} diff --git a/dev/conductor/core/lib/src/next.dart b/dev/conductor/core/lib/src/next.dart deleted file mode 100644 index 0323aaced4489..0000000000000 --- a/dev/conductor/core/lib/src/next.dart +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/command_runner.dart'; -import 'package:file/file.dart' show File; -import 'package:meta/meta.dart' show visibleForTesting; - -import 'context.dart'; -import 'git.dart'; -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'proto/conductor_state.pbenum.dart'; -import 'repository.dart'; -import 'state.dart' as state_import; - -const String kStateOption = 'state-file'; -const String kYesFlag = 'yes'; - -/// Command to proceed from one [pb.ReleasePhase] to the next. -/// -/// After `conductor start`, the rest of the release steps are initiated by the -/// user via `conductor next`. Thus this command's behavior is conditional upon -/// which phase of the release the user is currently in. This is implemented -/// with a switch case statement. -class NextCommand extends Command { - NextCommand({required this.checkouts}) { - final String defaultPath = state_import.defaultStateFilePath(checkouts.platform); - argParser.addOption( - kStateOption, - defaultsTo: defaultPath, - help: 'Path to persistent state file. Defaults to $defaultPath', - ); - argParser.addFlag( - kYesFlag, - help: 'Auto-accept any confirmation prompts.', - hide: true, // primarily for integration testing - ); - argParser.addFlag(kForceFlag, help: 'Force push when updating remote git branches.'); - } - - final Checkouts checkouts; - - @override - String get name => 'next'; - - @override - String get description => 'Proceed to the next release phase.'; - - @override - Future run() async { - final File stateFile = checkouts.fileSystem.file(argResults![kStateOption]); - if (!stateFile.existsSync()) { - throw ConductorException('No persistent state file found at ${stateFile.path}.'); - } - final pb.ConductorState state = state_import.readStateFromFile(stateFile); - - await NextContext( - autoAccept: argResults![kYesFlag] as bool, - checkouts: checkouts, - force: argResults![kForceFlag] as bool, - stateFile: stateFile, - ).run(state); - } -} - -/// Utility class for proceeding to the next step in a release. -/// -/// Any calls to functions that cause side effects are wrapped in methods to -/// allow overriding in unit tests. -class NextContext extends Context { - const NextContext({ - required this.autoAccept, - required this.force, - required super.checkouts, - required super.stateFile, - }); - - final bool autoAccept; - final bool force; - - Future run(pb.ConductorState state) async { - const List finishedStates = [ - CherrypickState.COMPLETED, - CherrypickState.ABANDONED, - ]; - switch (state.currentPhase) { - case pb.ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS: - final Remote upstream = Remote.upstream(state.framework.upstream.url); - final FrameworkRepository framework = FrameworkRepository( - checkouts, - initialRef: state.framework.workingBranch, - upstreamRemote: upstream, - previousCheckoutLocation: state.framework.checkoutPath, - ); - stdio.printStatus('Writing candidate branch...'); - final bool needsCommit = await framework.updateCandidateBranchVersion( - state.framework.candidateBranch, - ); - if (needsCommit) { - final String revision = await framework.commit( - 'Create candidate branch version ${state.framework.candidateBranch} for ${state.releaseChannel}', - addFirst: true, - ); - // append to list of cherrypicks so we know a PR is required - state.framework.cherrypicks.add( - pb.Cherrypick.create() - ..appliedRevision = revision - ..state = pb.CherrypickState.COMPLETED, - ); - } - - final List unappliedCherrypicks = [ - for (final pb.Cherrypick cherrypick in state.framework.cherrypicks) - if (!finishedStates.contains(cherrypick.state)) cherrypick, - ]; - - if (state.framework.cherrypicks.isEmpty) { - stdio.printStatus( - 'This release has no framework cherrypicks. However, a framework PR is still\n' - 'required to roll engine cherrypicks.', - ); - } else if (unappliedCherrypicks.isEmpty) { - stdio.printStatus('All framework cherrypicks were auto-applied by the conductor.'); - } else { - if (unappliedCherrypicks.length == 1) { - stdio.printStatus( - 'There was ${unappliedCherrypicks.length} cherrypick that was not auto-applied.', - ); - } else { - stdio.printStatus( - 'There were ${unappliedCherrypicks.length} cherrypicks that were not auto-applied.', - ); - } - stdio.printStatus( - 'These must be applied manually in the directory ' - '${state.framework.checkoutPath} before proceeding.\n', - ); - } - - if (!autoAccept) { - final bool response = await prompt( - 'Are you ready to push your framework branch to the repository ' - '${state.framework.mirror.url}?', - ); - if (!response) { - stdio.printError('Aborting command.'); - updateState(state, stdio.logs); - return; - } - } - - await pushWorkingBranch(framework, state.framework); - case pb.ReleasePhase.UPDATE_ENGINE_VERSION: - final Remote upstream = Remote.upstream(state.framework.upstream.url); - final FrameworkRepository framework = FrameworkRepository( - checkouts, - initialRef: state.framework.workingBranch, - upstreamRemote: upstream, - previousCheckoutLocation: state.framework.checkoutPath, - ); - final String rev = await framework.reverseParse('HEAD'); - final File engineVersionFile = (await framework.checkoutDirectory) - .childDirectory('bin') - .childDirectory('internal') - .childFile('engine.version'); - - engineVersionFile.writeAsStringSync(rev); - - // Must force add since it is gitignored - await framework.git.run( - const ['add', 'bin/internal/engine.version', '--force'], - 'adding engine.version file', - workingDirectory: (await framework.checkoutDirectory).path, - ); - final String revision = await framework.commit( - 'Create engine.version file pointing to $rev', - ); - // append to list of cherrypicks so we know a PR is required - state.framework.cherrypicks.add( - pb.Cherrypick.create() - ..appliedRevision = revision - ..state = pb.CherrypickState.COMPLETED, - ); - - if (!autoAccept) { - final bool response = await prompt( - 'Are you ready to push your framework branch to the repository ' - '${state.framework.mirror.url}?', - ); - if (!response) { - stdio.printError('Aborting command.'); - updateState(state, stdio.logs); - return; - } - } - - await pushWorkingBranch(framework, state.framework); - case pb.ReleasePhase.PUBLISH_VERSION: - final String command = ''' - tool-proxy-cli --tool_proxy=/abns/dart-eng-tool-proxy/prod-dart-eng-tool-proxy-tool-proxy.annealed-tool-proxy \\ - --block_on_mpa -I flutter_release \\ - :git_branch ${state.framework.candidateBranch} \\ - :release_channel ${state.releaseChannel} \\ - :tag ${state.releaseVersion} \\ - :force false - '''; - stdio.printStatus('Please ensure that you have merged your framework PR'); - stdio.printStatus('and post-submit CI has finished successfully.\n'); - stdio.printStatus('Run the following command, and ask a Googler'); - stdio.printStatus('to review the request\n\n$command'); - case pb.ReleasePhase.VERIFY_RELEASE: - stdio.printStatus( - 'The current status of packaging builds can be seen at:\n' - '\t$kLuciPackagingConsoleLink', - ); - if (!autoAccept) { - final bool response = await prompt( - 'Have all packaging builds finished successfully and post release announcements been completed?', - ); - if (!response) { - stdio.printError('Aborting command.'); - updateState(state, stdio.logs); - return; - } - } - case pb.ReleasePhase.RELEASE_COMPLETED: - throw ConductorException('This release is finished.'); - } - final ReleasePhase nextPhase = state_import.getNextPhase(state.currentPhase); - stdio.printStatus('\nUpdating phase from ${state.currentPhase} to $nextPhase...\n'); - state.currentPhase = nextPhase; - stdio.printStatus(state_import.phaseInstructions(state)); - - updateState(state, stdio.logs); - } - - /// Push the working branch to the user's mirror. - /// - /// [repository] represents the actual Git repository on disk, and is used to - /// call `git push`, while [pbRepository] represents the user-specified - /// configuration for the repository, and is used to read the name of the - /// working branch and the mirror's remote name. - /// - /// May throw either a [ConductorException] if the user already has a branch - /// of the same name on their mirror, or a [GitException] for any other - /// failures from the underlying git process call. - @visibleForTesting - Future pushWorkingBranch(Repository repository, pb.Repository pbRepository) async { - try { - await repository.pushRef( - fromRef: 'HEAD', - // Explicitly create new branch - toRef: 'refs/heads/${pbRepository.workingBranch}', - remote: pbRepository.mirror.name, - force: force, - ); - } on GitException catch (exception) { - if (exception.type == GitExceptionType.PushRejected && !force) { - throw ConductorException( - 'Push failed because the working branch named ' - '${pbRepository.workingBranch} already exists on your mirror. ' - 'Re-run this command with --force to overwrite the remote branch.\n' - '${exception.message}', - ); - } - rethrow; - } - } -} diff --git a/dev/conductor/core/lib/src/packages_autoroller.dart b/dev/conductor/core/lib/src/packages_autoroller.dart index 46dc4e79b689a..4f75a4eaede73 100644 --- a/dev/conductor/core/lib/src/packages_autoroller.dart +++ b/dev/conductor/core/lib/src/packages_autoroller.dart @@ -154,7 +154,7 @@ This PR was generated by the automated ) async { final String entrypoint = '${repoRoot.path}/dev/tools/bin/generate_gradle_lockfiles.dart'; final File target = tempDir.childFile('generate_gradle_lockfiles'); - await framework.streamDart([ + await framework.streamFlutter([ 'pub', 'get', ], workingDirectory: '${repoRoot.path}/dev/tools'); diff --git a/dev/conductor/core/lib/src/proto/compile_proto.sh b/dev/conductor/core/lib/src/proto/compile_proto.sh deleted file mode 100755 index 26f049936a9d4..0000000000000 --- a/dev/conductor/core/lib/src/proto/compile_proto.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2014 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -set -euo pipefail - -function follow_links() ( - cd -P "$(dirname -- "$1")" - file="$PWD/$(basename -- "$1")" - while [[ -h "$file" ]]; do - cd -P "$(dirname -- "$file")" - file="$(readlink -- "$file")" - cd -P "$(dirname -- "$file")" - file="$PWD/$(basename -- "$file")" - done - echo "$file" -) - -PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")" -DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" - -# Ensure dart-sdk is cached -"$DIR/../../../../../../bin/dart" --version - -if ! type protoc >/dev/null 2>&1; then - PROTOC_LINK='https://grpc.io/docs/protoc-installation/' - echo "Error! \"protoc\" binary required on path." - echo "See $PROTOC_LINK for more information." - exit 1 -fi - -if ! type dart >/dev/null 2>&1; then - echo "Error! \"dart\" binary required on path." - exit 1 -fi - -# Use null-safe protoc_plugin -dart pub global activate protoc_plugin 21.1.2 - -protoc --dart_out="$DIR" --proto_path="$DIR" "$DIR/conductor_state.proto" - -for SOURCE_FILE in $(ls "$DIR"/*.pb*.dart); do - # Format in place file - dart format --output=write "$SOURCE_FILE" - - # Create temp copy with the license header prepended - cp "$DIR/license_header.txt" "${SOURCE_FILE}.tmp" - - # Add an extra newline required by analysis (analysis also prevents - # license_header.txt from having the trailing newline) - echo '' >> "${SOURCE_FILE}.tmp" - - cat "$SOURCE_FILE" >> "${SOURCE_FILE}.tmp" - - # Move temp version (with license) over the original - mv "${SOURCE_FILE}.tmp" "$SOURCE_FILE" -done diff --git a/dev/conductor/core/lib/src/proto/conductor_state.pb.dart b/dev/conductor/core/lib/src/proto/conductor_state.pb.dart deleted file mode 100644 index 55d3ae9fcfbd1..0000000000000 --- a/dev/conductor/core/lib/src/proto/conductor_state.pb.dart +++ /dev/null @@ -1,625 +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. - -// -// Generated code. Do not modify. -// source: conductor_state.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:core' as $core; - -import 'package:fixnum/fixnum.dart' as $fixnum; -import 'package:protobuf/protobuf.dart' as $pb; - -import 'conductor_state.pbenum.dart'; - -export 'conductor_state.pbenum.dart'; - -/// A git remote -class Remote extends $pb.GeneratedMessage { - factory Remote({ - $core.String? name, - $core.String? url, - }) { - final $result = create(); - if (name != null) { - $result.name = name; - } - if (url != null) { - $result.url = url; - } - return $result; - } - Remote._() : super(); - factory Remote.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory Remote.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Remote', - package: const $pb.PackageName(_omitMessageNames ? '' : 'conductor_state'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'name') - ..aOS(2, _omitFieldNames ? '' : 'url') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - Remote clone() => Remote()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Remote copyWith(void Function(Remote) updates) => - super.copyWith((message) => updates(message as Remote)) as Remote; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static Remote create() => Remote._(); - Remote createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static Remote getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Remote? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get name => $_getSZ(0); - @$pb.TagNumber(1) - set name($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasName() => $_has(0); - @$pb.TagNumber(1) - void clearName() => clearField(1); - - @$pb.TagNumber(2) - $core.String get url => $_getSZ(1); - @$pb.TagNumber(2) - set url($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasUrl() => $_has(1); - @$pb.TagNumber(2) - void clearUrl() => clearField(2); -} - -class Cherrypick extends $pb.GeneratedMessage { - factory Cherrypick({ - $core.String? trunkRevision, - $core.String? appliedRevision, - CherrypickState? state, - }) { - final $result = create(); - if (trunkRevision != null) { - $result.trunkRevision = trunkRevision; - } - if (appliedRevision != null) { - $result.appliedRevision = appliedRevision; - } - if (state != null) { - $result.state = state; - } - return $result; - } - Cherrypick._() : super(); - factory Cherrypick.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory Cherrypick.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Cherrypick', - package: const $pb.PackageName(_omitMessageNames ? '' : 'conductor_state'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'trunkRevision', protoName: 'trunkRevision') - ..aOS(2, _omitFieldNames ? '' : 'appliedRevision', protoName: 'appliedRevision') - ..e(3, _omitFieldNames ? '' : 'state', $pb.PbFieldType.OE, - defaultOrMaker: CherrypickState.PENDING, - valueOf: CherrypickState.valueOf, - enumValues: CherrypickState.values) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - Cherrypick clone() => Cherrypick()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Cherrypick copyWith(void Function(Cherrypick) updates) => - super.copyWith((message) => updates(message as Cherrypick)) as Cherrypick; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static Cherrypick create() => Cherrypick._(); - Cherrypick createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static Cherrypick getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Cherrypick? _defaultInstance; - - /// The revision on trunk to cherrypick. - @$pb.TagNumber(1) - $core.String get trunkRevision => $_getSZ(0); - @$pb.TagNumber(1) - set trunkRevision($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasTrunkRevision() => $_has(0); - @$pb.TagNumber(1) - void clearTrunkRevision() => clearField(1); - - /// Once applied, the actual commit revision of the cherrypick. - @$pb.TagNumber(2) - $core.String get appliedRevision => $_getSZ(1); - @$pb.TagNumber(2) - set appliedRevision($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasAppliedRevision() => $_has(1); - @$pb.TagNumber(2) - void clearAppliedRevision() => clearField(2); - - @$pb.TagNumber(3) - CherrypickState get state => $_getN(2); - @$pb.TagNumber(3) - set state(CherrypickState v) { - setField(3, v); - } - - @$pb.TagNumber(3) - $core.bool hasState() => $_has(2); - @$pb.TagNumber(3) - void clearState() => clearField(3); -} - -class Repository extends $pb.GeneratedMessage { - factory Repository({ - $core.String? candidateBranch, - $core.String? startingGitHead, - $core.String? currentGitHead, - $core.String? checkoutPath, - Remote? upstream, - Remote? mirror, - $core.Iterable? cherrypicks, - $core.String? dartRevision, - $core.String? workingBranch, - }) { - final $result = create(); - if (candidateBranch != null) { - $result.candidateBranch = candidateBranch; - } - if (startingGitHead != null) { - $result.startingGitHead = startingGitHead; - } - if (currentGitHead != null) { - $result.currentGitHead = currentGitHead; - } - if (checkoutPath != null) { - $result.checkoutPath = checkoutPath; - } - if (upstream != null) { - $result.upstream = upstream; - } - if (mirror != null) { - $result.mirror = mirror; - } - if (cherrypicks != null) { - $result.cherrypicks.addAll(cherrypicks); - } - if (dartRevision != null) { - $result.dartRevision = dartRevision; - } - if (workingBranch != null) { - $result.workingBranch = workingBranch; - } - return $result; - } - Repository._() : super(); - factory Repository.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory Repository.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Repository', - package: const $pb.PackageName(_omitMessageNames ? '' : 'conductor_state'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'candidateBranch', protoName: 'candidateBranch') - ..aOS(2, _omitFieldNames ? '' : 'startingGitHead', protoName: 'startingGitHead') - ..aOS(3, _omitFieldNames ? '' : 'currentGitHead', protoName: 'currentGitHead') - ..aOS(4, _omitFieldNames ? '' : 'checkoutPath', protoName: 'checkoutPath') - ..aOM(5, _omitFieldNames ? '' : 'upstream', subBuilder: Remote.create) - ..aOM(6, _omitFieldNames ? '' : 'mirror', subBuilder: Remote.create) - ..pc(7, _omitFieldNames ? '' : 'cherrypicks', $pb.PbFieldType.PM, - subBuilder: Cherrypick.create) - ..aOS(8, _omitFieldNames ? '' : 'dartRevision', protoName: 'dartRevision') - ..aOS(9, _omitFieldNames ? '' : 'workingBranch', protoName: 'workingBranch') - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - Repository clone() => Repository()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - Repository copyWith(void Function(Repository) updates) => - super.copyWith((message) => updates(message as Repository)) as Repository; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static Repository create() => Repository._(); - Repository createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static Repository getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static Repository? _defaultInstance; - - /// The development git branch the release is based on. - /// - /// Must be of the form /flutter-(\d+)\.(\d+)-candidate\.(\d+)/ - @$pb.TagNumber(1) - $core.String get candidateBranch => $_getSZ(0); - @$pb.TagNumber(1) - set candidateBranch($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasCandidateBranch() => $_has(0); - @$pb.TagNumber(1) - void clearCandidateBranch() => clearField(1); - - /// The commit hash at the tip of the branch before cherrypicks were applied. - @$pb.TagNumber(2) - $core.String get startingGitHead => $_getSZ(1); - @$pb.TagNumber(2) - set startingGitHead($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasStartingGitHead() => $_has(1); - @$pb.TagNumber(2) - void clearStartingGitHead() => clearField(2); - - /// The difference in commits between this and [startingGitHead] is the number - /// of cherrypicks that have been currently applied. - @$pb.TagNumber(3) - $core.String get currentGitHead => $_getSZ(2); - @$pb.TagNumber(3) - set currentGitHead($core.String v) { - $_setString(2, v); - } - - @$pb.TagNumber(3) - $core.bool hasCurrentGitHead() => $_has(2); - @$pb.TagNumber(3) - void clearCurrentGitHead() => clearField(3); - - /// Path to the git checkout on local disk. - @$pb.TagNumber(4) - $core.String get checkoutPath => $_getSZ(3); - @$pb.TagNumber(4) - set checkoutPath($core.String v) { - $_setString(3, v); - } - - @$pb.TagNumber(4) - $core.bool hasCheckoutPath() => $_has(3); - @$pb.TagNumber(4) - void clearCheckoutPath() => clearField(4); - - /// The remote commits will be fetched from. - @$pb.TagNumber(5) - Remote get upstream => $_getN(4); - @$pb.TagNumber(5) - set upstream(Remote v) { - setField(5, v); - } - - @$pb.TagNumber(5) - $core.bool hasUpstream() => $_has(4); - @$pb.TagNumber(5) - void clearUpstream() => clearField(5); - @$pb.TagNumber(5) - Remote ensureUpstream() => $_ensure(4); - - /// The remote cherrypicks will be pushed to create a Pull Request. - /// - /// This should be a mirror owned by the user conducting the release. - @$pb.TagNumber(6) - Remote get mirror => $_getN(5); - @$pb.TagNumber(6) - set mirror(Remote v) { - setField(6, v); - } - - @$pb.TagNumber(6) - $core.bool hasMirror() => $_has(5); - @$pb.TagNumber(6) - void clearMirror() => clearField(6); - @$pb.TagNumber(6) - Remote ensureMirror() => $_ensure(5); - - /// Desired cherrypicks. - @$pb.TagNumber(7) - $core.List get cherrypicks => $_getList(6); - - /// For the repository that has a dart_revision in a DEPS file. - @$pb.TagNumber(8) - $core.String get dartRevision => $_getSZ(7); - @$pb.TagNumber(8) - set dartRevision($core.String v) { - $_setString(7, v); - } - - @$pb.TagNumber(8) - $core.bool hasDartRevision() => $_has(7); - @$pb.TagNumber(8) - void clearDartRevision() => clearField(8); - - /// Name of local and remote branch for applying cherrypicks. - /// - /// When the pull request is merged, all commits here will be squashed to a - /// single commit on the [candidateBranch]. - @$pb.TagNumber(9) - $core.String get workingBranch => $_getSZ(8); - @$pb.TagNumber(9) - set workingBranch($core.String v) { - $_setString(8, v); - } - - @$pb.TagNumber(9) - $core.bool hasWorkingBranch() => $_has(8); - @$pb.TagNumber(9) - void clearWorkingBranch() => clearField(9); -} - -class ConductorState extends $pb.GeneratedMessage { - factory ConductorState({ - $core.String? releaseChannel, - $core.String? releaseVersion, - Repository? engine, - Repository? framework, - $fixnum.Int64? createdDate, - $fixnum.Int64? lastUpdatedDate, - $core.Iterable<$core.String>? logs, - ReleasePhase? currentPhase, - $core.String? conductorVersion, - ReleaseType? releaseType, - }) { - final $result = create(); - if (releaseChannel != null) { - $result.releaseChannel = releaseChannel; - } - if (releaseVersion != null) { - $result.releaseVersion = releaseVersion; - } - if (engine != null) { - $result.engine = engine; - } - if (framework != null) { - $result.framework = framework; - } - if (createdDate != null) { - $result.createdDate = createdDate; - } - if (lastUpdatedDate != null) { - $result.lastUpdatedDate = lastUpdatedDate; - } - if (logs != null) { - $result.logs.addAll(logs); - } - if (currentPhase != null) { - $result.currentPhase = currentPhase; - } - if (conductorVersion != null) { - $result.conductorVersion = conductorVersion; - } - if (releaseType != null) { - $result.releaseType = releaseType; - } - return $result; - } - ConductorState._() : super(); - factory ConductorState.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory ConductorState.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - - static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ConductorState', - package: const $pb.PackageName(_omitMessageNames ? '' : 'conductor_state'), - createEmptyInstance: create) - ..aOS(1, _omitFieldNames ? '' : 'releaseChannel', protoName: 'releaseChannel') - ..aOS(2, _omitFieldNames ? '' : 'releaseVersion', protoName: 'releaseVersion') - ..aOM(4, _omitFieldNames ? '' : 'engine', subBuilder: Repository.create) - ..aOM(5, _omitFieldNames ? '' : 'framework', subBuilder: Repository.create) - ..aInt64(6, _omitFieldNames ? '' : 'createdDate', protoName: 'createdDate') - ..aInt64(7, _omitFieldNames ? '' : 'lastUpdatedDate', protoName: 'lastUpdatedDate') - ..pPS(8, _omitFieldNames ? '' : 'logs') - ..e(9, _omitFieldNames ? '' : 'currentPhase', $pb.PbFieldType.OE, - protoName: 'currentPhase', - defaultOrMaker: ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS, - valueOf: ReleasePhase.valueOf, - enumValues: ReleasePhase.values) - ..aOS(10, _omitFieldNames ? '' : 'conductorVersion', protoName: 'conductorVersion') - ..e(11, _omitFieldNames ? '' : 'releaseType', $pb.PbFieldType.OE, - protoName: 'releaseType', - defaultOrMaker: ReleaseType.STABLE_INITIAL, - valueOf: ReleaseType.valueOf, - enumValues: ReleaseType.values) - ..hasRequiredFields = false; - - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - ConductorState clone() => ConductorState()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - ConductorState copyWith(void Function(ConductorState) updates) => - super.copyWith((message) => updates(message as ConductorState)) as ConductorState; - - $pb.BuilderInfo get info_ => _i; - - @$core.pragma('dart2js:noInline') - static ConductorState create() => ConductorState._(); - ConductorState createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static ConductorState getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ConductorState? _defaultInstance; - - /// One of 'stable', 'beta', or 'dev' - @$pb.TagNumber(1) - $core.String get releaseChannel => $_getSZ(0); - @$pb.TagNumber(1) - set releaseChannel($core.String v) { - $_setString(0, v); - } - - @$pb.TagNumber(1) - $core.bool hasReleaseChannel() => $_has(0); - @$pb.TagNumber(1) - void clearReleaseChannel() => clearField(1); - - /// The name of the release. - @$pb.TagNumber(2) - $core.String get releaseVersion => $_getSZ(1); - @$pb.TagNumber(2) - set releaseVersion($core.String v) { - $_setString(1, v); - } - - @$pb.TagNumber(2) - $core.bool hasReleaseVersion() => $_has(1); - @$pb.TagNumber(2) - void clearReleaseVersion() => clearField(2); - - @$pb.TagNumber(4) - Repository get engine => $_getN(2); - @$pb.TagNumber(4) - set engine(Repository v) { - setField(4, v); - } - - @$pb.TagNumber(4) - $core.bool hasEngine() => $_has(2); - @$pb.TagNumber(4) - void clearEngine() => clearField(4); - @$pb.TagNumber(4) - Repository ensureEngine() => $_ensure(2); - - @$pb.TagNumber(5) - Repository get framework => $_getN(3); - @$pb.TagNumber(5) - set framework(Repository v) { - setField(5, v); - } - - @$pb.TagNumber(5) - $core.bool hasFramework() => $_has(3); - @$pb.TagNumber(5) - void clearFramework() => clearField(5); - @$pb.TagNumber(5) - Repository ensureFramework() => $_ensure(3); - - @$pb.TagNumber(6) - $fixnum.Int64 get createdDate => $_getI64(4); - @$pb.TagNumber(6) - set createdDate($fixnum.Int64 v) { - $_setInt64(4, v); - } - - @$pb.TagNumber(6) - $core.bool hasCreatedDate() => $_has(4); - @$pb.TagNumber(6) - void clearCreatedDate() => clearField(6); - - @$pb.TagNumber(7) - $fixnum.Int64 get lastUpdatedDate => $_getI64(5); - @$pb.TagNumber(7) - set lastUpdatedDate($fixnum.Int64 v) { - $_setInt64(5, v); - } - - @$pb.TagNumber(7) - $core.bool hasLastUpdatedDate() => $_has(5); - @$pb.TagNumber(7) - void clearLastUpdatedDate() => clearField(7); - - @$pb.TagNumber(8) - $core.List<$core.String> get logs => $_getList(6); - - /// The current [ReleasePhase] that has yet to be completed. - @$pb.TagNumber(9) - ReleasePhase get currentPhase => $_getN(7); - @$pb.TagNumber(9) - set currentPhase(ReleasePhase v) { - setField(9, v); - } - - @$pb.TagNumber(9) - $core.bool hasCurrentPhase() => $_has(7); - @$pb.TagNumber(9) - void clearCurrentPhase() => clearField(9); - - /// A string used to validate that the current conductor is the same version - /// that created the [ConductorState] object. - @$pb.TagNumber(10) - $core.String get conductorVersion => $_getSZ(8); - @$pb.TagNumber(10) - set conductorVersion($core.String v) { - $_setString(8, v); - } - - @$pb.TagNumber(10) - $core.bool hasConductorVersion() => $_has(8); - @$pb.TagNumber(10) - void clearConductorVersion() => clearField(10); - - @$pb.TagNumber(11) - ReleaseType get releaseType => $_getN(9); - @$pb.TagNumber(11) - set releaseType(ReleaseType v) { - setField(11, v); - } - - @$pb.TagNumber(11) - $core.bool hasReleaseType() => $_has(9); - @$pb.TagNumber(11) - void clearReleaseType() => clearField(11); -} - -const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); -const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/dev/conductor/core/lib/src/proto/conductor_state.pbenum.dart b/dev/conductor/core/lib/src/proto/conductor_state.pbenum.dart deleted file mode 100644 index a62cdfd86a542..0000000000000 --- a/dev/conductor/core/lib/src/proto/conductor_state.pbenum.dart +++ /dev/null @@ -1,90 +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. - -// -// Generated code. Do not modify. -// source: conductor_state.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:core' as $core; - -import 'package:protobuf/protobuf.dart' as $pb; - -class ReleasePhase extends $pb.ProtobufEnum { - static const ReleasePhase APPLY_FRAMEWORK_CHERRYPICKS = - ReleasePhase._(0, _omitEnumNames ? '' : 'APPLY_FRAMEWORK_CHERRYPICKS'); - static const ReleasePhase UPDATE_ENGINE_VERSION = - ReleasePhase._(1, _omitEnumNames ? '' : 'UPDATE_ENGINE_VERSION'); - static const ReleasePhase PUBLISH_VERSION = - ReleasePhase._(2, _omitEnumNames ? '' : 'PUBLISH_VERSION'); - static const ReleasePhase VERIFY_RELEASE = - ReleasePhase._(3, _omitEnumNames ? '' : 'VERIFY_RELEASE'); - static const ReleasePhase RELEASE_COMPLETED = - ReleasePhase._(4, _omitEnumNames ? '' : 'RELEASE_COMPLETED'); - - static const $core.List values = [ - APPLY_FRAMEWORK_CHERRYPICKS, - UPDATE_ENGINE_VERSION, - PUBLISH_VERSION, - VERIFY_RELEASE, - RELEASE_COMPLETED, - ]; - - static final $core.Map<$core.int, ReleasePhase> _byValue = $pb.ProtobufEnum.initByValue(values); - static ReleasePhase? valueOf($core.int value) => _byValue[value]; - - const ReleasePhase._($core.int v, $core.String n) : super(v, n); -} - -class CherrypickState extends $pb.ProtobufEnum { - static const CherrypickState PENDING = CherrypickState._(0, _omitEnumNames ? '' : 'PENDING'); - static const CherrypickState PENDING_WITH_CONFLICT = - CherrypickState._(1, _omitEnumNames ? '' : 'PENDING_WITH_CONFLICT'); - static const CherrypickState COMPLETED = CherrypickState._(2, _omitEnumNames ? '' : 'COMPLETED'); - static const CherrypickState ABANDONED = CherrypickState._(3, _omitEnumNames ? '' : 'ABANDONED'); - - static const $core.List values = [ - PENDING, - PENDING_WITH_CONFLICT, - COMPLETED, - ABANDONED, - ]; - - static final $core.Map<$core.int, CherrypickState> _byValue = - $pb.ProtobufEnum.initByValue(values); - static CherrypickState? valueOf($core.int value) => _byValue[value]; - - const CherrypickState._($core.int v, $core.String n) : super(v, n); -} - -/// The type of release that is being created. -/// -/// This determines how the version will be calculated. -class ReleaseType extends $pb.ProtobufEnum { - static const ReleaseType STABLE_INITIAL = - ReleaseType._(0, _omitEnumNames ? '' : 'STABLE_INITIAL'); - static const ReleaseType STABLE_HOTFIX = ReleaseType._(1, _omitEnumNames ? '' : 'STABLE_HOTFIX'); - static const ReleaseType BETA_INITIAL = ReleaseType._(2, _omitEnumNames ? '' : 'BETA_INITIAL'); - static const ReleaseType BETA_HOTFIX = ReleaseType._(3, _omitEnumNames ? '' : 'BETA_HOTFIX'); - - static const $core.List values = [ - STABLE_INITIAL, - STABLE_HOTFIX, - BETA_INITIAL, - BETA_HOTFIX, - ]; - - static final $core.Map<$core.int, ReleaseType> _byValue = $pb.ProtobufEnum.initByValue(values); - static ReleaseType? valueOf($core.int value) => _byValue[value]; - - const ReleaseType._($core.int v, $core.String n) : super(v, n); -} - -const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); diff --git a/dev/conductor/core/lib/src/proto/conductor_state.pbjson.dart b/dev/conductor/core/lib/src/proto/conductor_state.pbjson.dart deleted file mode 100644 index 53bf1cbc87bb5..0000000000000 --- a/dev/conductor/core/lib/src/proto/conductor_state.pbjson.dart +++ /dev/null @@ -1,181 +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. - -// -// Generated code. Do not modify. -// source: conductor_state.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -import 'dart:convert' as $convert; -import 'dart:core' as $core; -import 'dart:typed_data' as $typed_data; - -@$core.Deprecated('Use releasePhaseDescriptor instead') -const ReleasePhase$json = { - '1': 'ReleasePhase', - '2': [ - {'1': 'APPLY_FRAMEWORK_CHERRYPICKS', '2': 0}, - {'1': 'UPDATE_ENGINE_VERSION', '2': 1}, - {'1': 'PUBLISH_VERSION', '2': 2}, - {'1': 'VERIFY_RELEASE', '2': 3}, - {'1': 'RELEASE_COMPLETED', '2': 4}, - ], -}; - -/// Descriptor for `ReleasePhase`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List releasePhaseDescriptor = $convert - .base64Decode('CgxSZWxlYXNlUGhhc2USHwobQVBQTFlfRlJBTUVXT1JLX0NIRVJSWVBJQ0tTEAASGQoVVVBEQV' - 'RFX0VOR0lORV9WRVJTSU9OEAESEwoPUFVCTElTSF9WRVJTSU9OEAISEgoOVkVSSUZZX1JFTEVB' - 'U0UQAxIVChFSRUxFQVNFX0NPTVBMRVRFRBAE'); - -@$core.Deprecated('Use cherrypickStateDescriptor instead') -const CherrypickState$json = { - '1': 'CherrypickState', - '2': [ - {'1': 'PENDING', '2': 0}, - {'1': 'PENDING_WITH_CONFLICT', '2': 1}, - {'1': 'COMPLETED', '2': 2}, - {'1': 'ABANDONED', '2': 3}, - ], -}; - -/// Descriptor for `CherrypickState`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List cherrypickStateDescriptor = $convert - .base64Decode('Cg9DaGVycnlwaWNrU3RhdGUSCwoHUEVORElORxAAEhkKFVBFTkRJTkdfV0lUSF9DT05GTElDVB' - 'ABEg0KCUNPTVBMRVRFRBACEg0KCUFCQU5ET05FRBAD'); - -@$core.Deprecated('Use releaseTypeDescriptor instead') -const ReleaseType$json = { - '1': 'ReleaseType', - '2': [ - {'1': 'STABLE_INITIAL', '2': 0}, - {'1': 'STABLE_HOTFIX', '2': 1}, - {'1': 'BETA_INITIAL', '2': 2}, - {'1': 'BETA_HOTFIX', '2': 3}, - ], -}; - -/// Descriptor for `ReleaseType`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List releaseTypeDescriptor = $convert - .base64Decode('CgtSZWxlYXNlVHlwZRISCg5TVEFCTEVfSU5JVElBTBAAEhEKDVNUQUJMRV9IT1RGSVgQARIQCg' - 'xCRVRBX0lOSVRJQUwQAhIPCgtCRVRBX0hPVEZJWBAD'); - -@$core.Deprecated('Use remoteDescriptor instead') -const Remote$json = { - '1': 'Remote', - '2': [ - {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, - {'1': 'url', '3': 2, '4': 1, '5': 9, '10': 'url'}, - ], -}; - -/// Descriptor for `Remote`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List remoteDescriptor = - $convert.base64Decode('CgZSZW1vdGUSEgoEbmFtZRgBIAEoCVIEbmFtZRIQCgN1cmwYAiABKAlSA3VybA=='); - -@$core.Deprecated('Use cherrypickDescriptor instead') -const Cherrypick$json = { - '1': 'Cherrypick', - '2': [ - {'1': 'trunkRevision', '3': 1, '4': 1, '5': 9, '10': 'trunkRevision'}, - {'1': 'appliedRevision', '3': 2, '4': 1, '5': 9, '10': 'appliedRevision'}, - {'1': 'state', '3': 3, '4': 1, '5': 14, '6': '.conductor_state.CherrypickState', '10': 'state'}, - ], -}; - -/// Descriptor for `Cherrypick`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List cherrypickDescriptor = $convert - .base64Decode('CgpDaGVycnlwaWNrEiQKDXRydW5rUmV2aXNpb24YASABKAlSDXRydW5rUmV2aXNpb24SKAoPYX' - 'BwbGllZFJldmlzaW9uGAIgASgJUg9hcHBsaWVkUmV2aXNpb24SNgoFc3RhdGUYAyABKA4yIC5j' - 'b25kdWN0b3Jfc3RhdGUuQ2hlcnJ5cGlja1N0YXRlUgVzdGF0ZQ=='); - -@$core.Deprecated('Use repositoryDescriptor instead') -const Repository$json = { - '1': 'Repository', - '2': [ - {'1': 'candidateBranch', '3': 1, '4': 1, '5': 9, '10': 'candidateBranch'}, - {'1': 'startingGitHead', '3': 2, '4': 1, '5': 9, '10': 'startingGitHead'}, - {'1': 'currentGitHead', '3': 3, '4': 1, '5': 9, '10': 'currentGitHead'}, - {'1': 'checkoutPath', '3': 4, '4': 1, '5': 9, '10': 'checkoutPath'}, - {'1': 'upstream', '3': 5, '4': 1, '5': 11, '6': '.conductor_state.Remote', '10': 'upstream'}, - {'1': 'mirror', '3': 6, '4': 1, '5': 11, '6': '.conductor_state.Remote', '10': 'mirror'}, - { - '1': 'cherrypicks', - '3': 7, - '4': 3, - '5': 11, - '6': '.conductor_state.Cherrypick', - '10': 'cherrypicks' - }, - {'1': 'dartRevision', '3': 8, '4': 1, '5': 9, '10': 'dartRevision'}, - {'1': 'workingBranch', '3': 9, '4': 1, '5': 9, '10': 'workingBranch'}, - ], -}; - -/// Descriptor for `Repository`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List repositoryDescriptor = $convert - .base64Decode('CgpSZXBvc2l0b3J5EigKD2NhbmRpZGF0ZUJyYW5jaBgBIAEoCVIPY2FuZGlkYXRlQnJhbmNoEi' - 'gKD3N0YXJ0aW5nR2l0SGVhZBgCIAEoCVIPc3RhcnRpbmdHaXRIZWFkEiYKDmN1cnJlbnRHaXRI' - 'ZWFkGAMgASgJUg5jdXJyZW50R2l0SGVhZBIiCgxjaGVja291dFBhdGgYBCABKAlSDGNoZWNrb3' - 'V0UGF0aBIzCgh1cHN0cmVhbRgFIAEoCzIXLmNvbmR1Y3Rvcl9zdGF0ZS5SZW1vdGVSCHVwc3Ry' - 'ZWFtEi8KBm1pcnJvchgGIAEoCzIXLmNvbmR1Y3Rvcl9zdGF0ZS5SZW1vdGVSBm1pcnJvchI9Cg' - 'tjaGVycnlwaWNrcxgHIAMoCzIbLmNvbmR1Y3Rvcl9zdGF0ZS5DaGVycnlwaWNrUgtjaGVycnlw' - 'aWNrcxIiCgxkYXJ0UmV2aXNpb24YCCABKAlSDGRhcnRSZXZpc2lvbhIkCg13b3JraW5nQnJhbm' - 'NoGAkgASgJUg13b3JraW5nQnJhbmNo'); - -@$core.Deprecated('Use conductorStateDescriptor instead') -const ConductorState$json = { - '1': 'ConductorState', - '2': [ - {'1': 'releaseChannel', '3': 1, '4': 1, '5': 9, '10': 'releaseChannel'}, - {'1': 'releaseVersion', '3': 2, '4': 1, '5': 9, '10': 'releaseVersion'}, - {'1': 'engine', '3': 4, '4': 1, '5': 11, '6': '.conductor_state.Repository', '10': 'engine'}, - { - '1': 'framework', - '3': 5, - '4': 1, - '5': 11, - '6': '.conductor_state.Repository', - '10': 'framework' - }, - {'1': 'createdDate', '3': 6, '4': 1, '5': 3, '10': 'createdDate'}, - {'1': 'lastUpdatedDate', '3': 7, '4': 1, '5': 3, '10': 'lastUpdatedDate'}, - {'1': 'logs', '3': 8, '4': 3, '5': 9, '10': 'logs'}, - { - '1': 'currentPhase', - '3': 9, - '4': 1, - '5': 14, - '6': '.conductor_state.ReleasePhase', - '10': 'currentPhase' - }, - {'1': 'conductorVersion', '3': 10, '4': 1, '5': 9, '10': 'conductorVersion'}, - { - '1': 'releaseType', - '3': 11, - '4': 1, - '5': 14, - '6': '.conductor_state.ReleaseType', - '10': 'releaseType' - }, - ], -}; - -/// Descriptor for `ConductorState`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List conductorStateDescriptor = $convert - .base64Decode('Cg5Db25kdWN0b3JTdGF0ZRImCg5yZWxlYXNlQ2hhbm5lbBgBIAEoCVIOcmVsZWFzZUNoYW5uZW' - 'wSJgoOcmVsZWFzZVZlcnNpb24YAiABKAlSDnJlbGVhc2VWZXJzaW9uEjMKBmVuZ2luZRgEIAEo' - 'CzIbLmNvbmR1Y3Rvcl9zdGF0ZS5SZXBvc2l0b3J5UgZlbmdpbmUSOQoJZnJhbWV3b3JrGAUgAS' - 'gLMhsuY29uZHVjdG9yX3N0YXRlLlJlcG9zaXRvcnlSCWZyYW1ld29yaxIgCgtjcmVhdGVkRGF0' - 'ZRgGIAEoA1ILY3JlYXRlZERhdGUSKAoPbGFzdFVwZGF0ZWREYXRlGAcgASgDUg9sYXN0VXBkYX' - 'RlZERhdGUSEgoEbG9ncxgIIAMoCVIEbG9ncxJBCgxjdXJyZW50UGhhc2UYCSABKA4yHS5jb25k' - 'dWN0b3Jfc3RhdGUuUmVsZWFzZVBoYXNlUgxjdXJyZW50UGhhc2USKgoQY29uZHVjdG9yVmVyc2' - 'lvbhgKIAEoCVIQY29uZHVjdG9yVmVyc2lvbhI+CgtyZWxlYXNlVHlwZRgLIAEoDjIcLmNvbmR1' - 'Y3Rvcl9zdGF0ZS5SZWxlYXNlVHlwZVILcmVsZWFzZVR5cGU='); diff --git a/dev/conductor/core/lib/src/proto/conductor_state.pbserver.dart b/dev/conductor/core/lib/src/proto/conductor_state.pbserver.dart deleted file mode 100644 index 47ea59ca60bb8..0000000000000 --- a/dev/conductor/core/lib/src/proto/conductor_state.pbserver.dart +++ /dev/null @@ -1,17 +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. - -// -// Generated code. Do not modify. -// source: conductor_state.proto -// -// @dart = 2.12 - -// ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names -// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes -// ignore_for_file: non_constant_identifier_names, prefer_final_fields -// ignore_for_file: unnecessary_import, unnecessary_this, unused_import - -export 'conductor_state.pb.dart'; diff --git a/dev/conductor/core/lib/src/proto/conductor_state.proto b/dev/conductor/core/lib/src/proto/conductor_state.proto deleted file mode 100644 index 71c6eec1afa6e..0000000000000 --- a/dev/conductor/core/lib/src/proto/conductor_state.proto +++ /dev/null @@ -1,129 +0,0 @@ -syntax = "proto3"; - -package conductor_state; - -// A git remote -message Remote { - string name = 1; - string url = 2; -} - -enum ReleasePhase { - APPLY_FRAMEWORK_CHERRYPICKS = 0; - - UPDATE_ENGINE_VERSION = 1; - - // Git tag applied to framework RC branch HEAD and pushed upstream. - PUBLISH_VERSION = 2; - - // Package artifacts verified to exist on cloud storage. - VERIFY_RELEASE = 3; - - // There is no further work to be done. - RELEASE_COMPLETED = 4; -} - -enum CherrypickState { - // The cherrypick has not yet been applied. - PENDING = 0; - - // The cherrypick has not been applied and will require manual resolution. - PENDING_WITH_CONFLICT = 1; - - // The cherrypick has been successfully applied to the local checkout. - // - // This state requires Cherrypick.appliedRevision to also be set. - COMPLETED = 2; - - // The cherrypick will NOT be applied in this release. - ABANDONED = 3; -} - -// The type of release that is being created. -// -// This determines how the version will be calculated. -enum ReleaseType { - // All pre-release metadata from previous beta releases will be discarded. The - // z must be 0. - STABLE_INITIAL = 0; - - // Increment z. - STABLE_HOTFIX = 1; - - // Compute x, y, and m from the candidate branch name. z and n should be 0. - BETA_INITIAL = 2; - - // Increment n. - BETA_HOTFIX = 3; -} - -message Cherrypick { - // The revision on trunk to cherrypick. - string trunkRevision = 1; - - // Once applied, the actual commit revision of the cherrypick. - string appliedRevision = 2; - - CherrypickState state = 3; -} - -message Repository { - // The development git branch the release is based on. - // - // Must be of the form /flutter-(\d+)\.(\d+)-candidate\.(\d+)/ - string candidateBranch = 1; - - // The commit hash at the tip of the branch before cherrypicks were applied. - string startingGitHead = 2; - - // The difference in commits between this and [startingGitHead] is the number - // of cherrypicks that have been currently applied. - string currentGitHead = 3; - - // Path to the git checkout on local disk. - string checkoutPath = 4; - - // The remote commits will be fetched from. - Remote upstream = 5; - - // The remote cherrypicks will be pushed to create a Pull Request. - // - // This should be a mirror owned by the user conducting the release. - Remote mirror = 6; - - // Desired cherrypicks. - repeated Cherrypick cherrypicks = 7; - - // For the repository that has a dart_revision in a DEPS file. - string dartRevision = 8; - - // Name of local and remote branch for applying cherrypicks. - // - // When the pull request is merged, all commits here will be squashed to a - // single commit on the [candidateBranch]. - string workingBranch = 9; -} - -message ConductorState { - // One of 'stable', 'beta', or 'dev' - string releaseChannel = 1; - - // The name of the release. - string releaseVersion = 2; - - Repository engine = 4; - Repository framework = 5; - int64 createdDate = 6; - int64 lastUpdatedDate = 7; - - repeated string logs = 8; - - // The current [ReleasePhase] that has yet to be completed. - ReleasePhase currentPhase = 9; - - // A string used to validate that the current conductor is the same version - // that created the [ConductorState] object. - string conductorVersion = 10; - - ReleaseType releaseType = 11; -} diff --git a/dev/conductor/core/lib/src/repository.dart b/dev/conductor/core/lib/src/repository.dart index 112efb07b5fb9..ce40ee9dfb646 100644 --- a/dev/conductor/core/lib/src/repository.dart +++ b/dev/conductor/core/lib/src/repository.dart @@ -14,7 +14,6 @@ import 'package:process/process.dart'; import './git.dart'; import './globals.dart'; import './stdio.dart'; -import './version.dart'; /// Allowed git remote names. enum RemoteName { upstream, mirror } @@ -594,13 +593,14 @@ class FrameworkRepository extends Repository { List args, { void Function(String)? stdoutCallback, void Function(String)? stderrCallback, + String? workingDirectory, }) async { - final String workingDirectory = (await checkoutDirectory).path; + final String repoWorkingDirectory = (await checkoutDirectory).path; return _streamProcess([ - fileSystem.path.join(workingDirectory, 'bin', 'flutter'), + fileSystem.path.join(repoWorkingDirectory, 'bin', 'flutter'), ...args, - ], workingDirectory: workingDirectory); + ], workingDirectory: workingDirectory ?? repoWorkingDirectory); } Future _streamProcess( @@ -644,14 +644,6 @@ class FrameworkRepository extends Repository { await _ensureToolReady(); } - Future flutterVersion() async { - // Check version - final io.ProcessResult result = await runFlutter(['--version', '--machine']); - final Map versionJson = - jsonDecode(stdoutToString(result.stdout)) as Map; - return Version.fromString(versionJson['frameworkVersion'] as String); - } - /// Create a release candidate branch version file. /// /// This file allows for easily traversing what candidate branch was used diff --git a/dev/conductor/core/lib/src/start.dart b/dev/conductor/core/lib/src/start.dart deleted file mode 100644 index 495092c1bbbf5..0000000000000 --- a/dev/conductor/core/lib/src/start.dart +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/args.dart'; -import 'package:args/command_runner.dart'; -import 'package:file/file.dart'; -import 'package:fixnum/fixnum.dart'; -import 'package:meta/meta.dart'; -import 'package:platform/platform.dart'; -import 'package:process/process.dart'; - -import 'context.dart'; -import 'git.dart'; -import 'globals.dart'; -import 'proto/conductor_state.pb.dart' as pb; -import 'proto/conductor_state.pbenum.dart'; -import 'repository.dart'; -import 'state.dart' as state_import; -import 'stdio.dart'; -import 'version.dart'; - -const String kCandidateOption = 'candidate-branch'; -const String kDartRevisionOption = 'dart-revision'; -const String kEngineUpstreamOption = 'engine-upstream'; -const String kFrameworkMirrorOption = 'framework-mirror'; -const String kFrameworkUpstreamOption = 'framework-upstream'; -const String kEngineMirrorOption = 'engine-mirror'; -const String kReleaseOption = 'release-channel'; -const String kStateOption = 'state-file'; -const String kVersionOverrideOption = 'version-override'; -const String kGithubUsernameOption = 'github-username'; - -/// Command to print the status of the current Flutter release. -/// -/// This command has many required options which the user must provide -/// via command line arguments (or optionally environment variables). -/// -/// This command is the one with the worst user experience (as the user has to -/// carefully type out many different options into their terminal) and the one -/// that would benefit the most from a GUI frontend. This command will -/// optionally read its options from an environment variable to facilitate a workflow -/// in which configuration is provided by editing a bash script that sets environment -/// variables and then invokes the conductor tool. -class StartCommand extends Command { - StartCommand({required this.checkouts, required this.conductorVersion}) - : platform = checkouts.platform, - processManager = checkouts.processManager, - fileSystem = checkouts.fileSystem, - stdio = checkouts.stdio { - final String defaultPath = state_import.defaultStateFilePath(platform); - argParser.addOption( - kCandidateOption, - help: 'The candidate branch the release will be based on.', - ); - argParser.addOption( - kReleaseOption, - help: 'The target release channel for the release.', - allowed: kBaseReleaseChannels, - ); - argParser.addOption(kFrameworkMirrorOption, help: 'Configurable Framework repo mirror remote.'); - argParser.addOption( - kFrameworkUpstreamOption, - defaultsTo: FrameworkRepository.defaultUpstream, - help: 'Configurable Framework repo upstream remote. Primarily for testing.', - hide: true, - ); - argParser.addOption( - kStateOption, - defaultsTo: defaultPath, - help: 'Path to persistent state file. Defaults to $defaultPath', - ); - argParser.addOption(kDartRevisionOption, help: 'New Dart revision to cherrypick.'); - argParser.addFlag( - kForceFlag, - abbr: 'f', - help: 'Override all validations of the command line inputs.', - ); - argParser.addOption( - kVersionOverrideOption, - help: - 'Explicitly set the desired version. This should only be used if ' - 'the version computed by the tool is not correct.', - ); - argParser.addOption(kGithubUsernameOption, help: 'Github username'); - } - - final Checkouts checkouts; - - final String conductorVersion; - final FileSystem fileSystem; - final Platform platform; - final ProcessManager processManager; - final Stdio stdio; - - @override - String get name => 'start'; - - @override - String get description => 'Initialize a new Flutter release.'; - - @visibleForTesting - StartContext createContext(ArgResults argumentResults) { - final String frameworkUpstream = - getValueFromEnvOrArgs(kFrameworkUpstreamOption, argumentResults, platform.environment)!; - final String githubUsername = - getValueFromEnvOrArgs(kGithubUsernameOption, argumentResults, platform.environment)!; - final String frameworkMirror = - getValueFromEnvOrArgs( - kFrameworkMirrorOption, - argumentResults, - platform.environment, - allowNull: true, - ) ?? - 'git@github.com:$githubUsername/flutter.git'; - final String candidateBranch = - getValueFromEnvOrArgs(kCandidateOption, argumentResults, platform.environment)!; - final String releaseChannel = - getValueFromEnvOrArgs(kReleaseOption, argumentResults, platform.environment)!; - final String? dartRevision = getValueFromEnvOrArgs( - kDartRevisionOption, - argumentResults, - platform.environment, - allowNull: true, - ); - final bool force = getBoolFromEnvOrArgs(kForceFlag, argumentResults, platform.environment); - final File stateFile = checkouts.fileSystem.file( - getValueFromEnvOrArgs(kStateOption, argumentResults, platform.environment), - ); - final String? versionOverrideString = getValueFromEnvOrArgs( - kVersionOverrideOption, - argumentResults, - platform.environment, - allowNull: true, - ); - Version? versionOverride; - if (versionOverrideString != null) { - versionOverride = Version.fromString(versionOverrideString); - } - - return StartContext( - candidateBranch: candidateBranch, - checkouts: checkouts, - dartRevision: dartRevision, - conductorVersion: conductorVersion, - frameworkMirror: frameworkMirror, - frameworkUpstream: frameworkUpstream, - processManager: processManager, - releaseChannel: releaseChannel, - stateFile: stateFile, - force: force, - versionOverride: versionOverride, - githubUsername: githubUsername, - ); - } - - @override - Future run() async { - final ArgResults argumentResults = argResults!; - if (!platform.isMacOS && !platform.isLinux) { - throw ConductorException('Error! This tool is only supported on macOS and Linux'); - } - - return createContext(argumentResults).run(); - } -} - -/// Context for starting a new release. -/// -/// This is a frontend-agnostic implementation. -class StartContext extends Context { - StartContext({ - required this.candidateBranch, - required this.dartRevision, - required this.frameworkMirror, - required this.frameworkUpstream, - required this.conductorVersion, - required this.processManager, - required this.releaseChannel, - required this.githubUsername, - required super.checkouts, - required super.stateFile, - this.force = false, - this.versionOverride, - }) : git = Git(processManager), - framework = FrameworkRepository( - checkouts, - initialRef: 'upstream/$candidateBranch', - upstreamRemote: Remote.upstream(frameworkUpstream), - mirrorRemote: Remote.mirror(frameworkMirror), - ); - - final String candidateBranch; - final String? dartRevision; - final String frameworkMirror; - final String frameworkUpstream; - final String conductorVersion; - final Git git; - final ProcessManager processManager; - final String releaseChannel; - final Version? versionOverride; - final String githubUsername; - - /// If validations should be overridden. - final bool force; - - final FrameworkRepository framework; - - /// Determine which part of the version to increment in the next release. - /// - /// If [atBranchPoint] is true, then this is a [ReleaseType.BETA_INITIAL]. - @visibleForTesting - ReleaseType computeReleaseType(Version lastVersion, bool atBranchPoint) { - if (atBranchPoint) { - return ReleaseType.BETA_INITIAL; - } - if (releaseChannel != 'stable') { - return ReleaseType.BETA_HOTFIX; - } - - return switch (lastVersion.type) { - VersionType.stable => ReleaseType.STABLE_HOTFIX, - VersionType.development || - VersionType.gitDescribe || - VersionType.latest => ReleaseType.STABLE_INITIAL, - }; - } - - Future run() async { - if (stateFile.existsSync()) { - throw ConductorException( - 'Error! A persistent state file already found at ${stateFile.path}.\n\n' - 'Run `conductor clean` to cancel a previous release.', - ); - } - if (!releaseCandidateBranchRegex.hasMatch(candidateBranch)) { - throw ConductorException( - 'Invalid release candidate branch "$candidateBranch". Text should ' - 'match the regex pattern /${releaseCandidateBranchRegex.pattern}/.', - ); - } - - final Int64 unixDate = Int64(DateTime.now().millisecondsSinceEpoch); - final pb.ConductorState state = pb.ConductorState(); - - state.releaseChannel = releaseChannel; - state.createdDate = unixDate; - state.lastUpdatedDate = unixDate; - - // Create a new branch so that we don't accidentally push to upstream - // candidateBranch. - final String workingBranchName = 'cherrypicks-$candidateBranch'; - - final String frameworkHead = await framework.reverseParse('HEAD'); - state.framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..workingBranch = workingBranchName - ..startingGitHead = frameworkHead - ..currentGitHead = frameworkHead - ..checkoutPath = (await framework.checkoutDirectory).path - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = framework.upstreamRemote.url) - ..mirror = - (pb.Remote.create() - ..name = 'mirror' - ..url = framework.mirrorRemote!.url)); - - if (dartRevision != null && dartRevision!.isNotEmpty) { - // In the monorepo, the DEPS file is in flutter/flutter - state.framework.dartRevision = dartRevision!; - } - - // Get framework version - final Version lastVersion = Version.fromString( - await framework.getFullTag(framework.upstreamRemote.name, candidateBranch, exact: false), - ); - - final String branchPoint = await framework.branchPoint( - '${framework.upstreamRemote.name}/$candidateBranch', - '${framework.upstreamRemote.name}/${FrameworkRepository.defaultBranch}', - ); - final bool atBranchPoint = branchPoint == frameworkHead; - - final ReleaseType releaseType = computeReleaseType(lastVersion, atBranchPoint); - state.releaseType = releaseType; - - Version nextVersion; - if (versionOverride != null) { - nextVersion = versionOverride!; - } else { - nextVersion = calculateNextVersion(lastVersion, releaseType); - nextVersion = await ensureBranchPointTagged( - branchPoint: branchPoint, - requestedVersion: nextVersion, - framework: framework, - ); - } - - await framework.newBranch(workingBranchName); - if (dartRevision != null && dartRevision!.isNotEmpty) { - await framework.updateDartRevision(dartRevision!); - await framework.commit('Update Dart SDK to $dartRevision', addFirst: true); - } - - state.releaseVersion = nextVersion.toString(); - - state.currentPhase = ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS; - - state.conductorVersion = conductorVersion; - - stdio.printTrace('Writing state to file ${stateFile.path}...'); - - updateState(state, stdio.logs); - - stdio.printStatus(state_import.presentState(state)); - } - - /// Determine this release's version number from the [lastVersion] and the [incrementLetter]. - Version calculateNextVersion(Version lastVersion, ReleaseType releaseType) { - return switch (releaseType) { - ReleaseType.STABLE_INITIAL => Version( - x: lastVersion.x, - y: lastVersion.y, - z: 0, - type: VersionType.stable, - ), - ReleaseType.STABLE_HOTFIX => Version.increment(lastVersion, 'z'), - ReleaseType.BETA_INITIAL => Version.fromCandidateBranch(candidateBranch), - ReleaseType.BETA_HOTFIX || _ => Version.increment(lastVersion, 'n'), - }; - } - - /// Ensures the branch point [candidateBranch] and `master` has a version tag. - /// - /// This is necessary for version reporting for users on the `master` channel - /// to be correct. - Future ensureBranchPointTagged({ - required Version requestedVersion, - required String branchPoint, - required FrameworkRepository framework, - }) async { - if (await framework.isCommitTagged(branchPoint)) { - // The branch point is tagged, no work to be done - return requestedVersion; - } - if (requestedVersion.n != 0) { - stdio.printError( - 'Tried to tag the branch point, however the target version is ' - '$requestedVersion, which does not have n == 0!', - ); - return requestedVersion; - } - - final bool response = await prompt( - 'About to tag the release candidate branch branchpoint of $branchPoint ' - 'as $requestedVersion and push it to ${framework.upstreamRemote.url}. ' - 'Is this correct?', - ); - - if (!response) { - throw ConductorException('Aborting command.'); - } - - stdio.printStatus('Applying the tag $requestedVersion at the branch point $branchPoint'); - - await framework.tag(branchPoint, requestedVersion.toString(), frameworkUpstream); - final Version nextVersion = Version.increment(requestedVersion, 'n'); - stdio.printStatus('The actual release will be version $nextVersion.'); - return nextVersion; - } -} diff --git a/dev/conductor/core/lib/src/state.dart b/dev/conductor/core/lib/src/state.dart deleted file mode 100644 index 24389f376c36b..0000000000000 --- a/dev/conductor/core/lib/src/state.dart +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert' show JsonEncoder, jsonDecode; - -import 'package:file/file.dart' show File; -import 'package:platform/platform.dart'; - -import './globals.dart' as globals; -import './proto/conductor_state.pb.dart' as pb; -import './proto/conductor_state.pbenum.dart' show ReleasePhase; - -const String kStateFileName = '.flutter_conductor_state.json'; - -const String betaPostReleaseMsg = """ - 'Ensure the following post release steps are complete:', - '\t 1. Post announcement to discord and press the publish button', - '\t\t Discord: ${globals.discordReleaseChannel}', - '\t 2. Post announcement flutter release hotline chat room', - '\t\t Chatroom: ${globals.flutterReleaseHotline}', -"""; - -const String stablePostReleaseMsg = """ - 'Ensure the following post release steps are complete:', - '\t 1. Update hotfix to stable wiki following documentation best practices', - '\t\t Wiki link: ${globals.hotfixToStableWiki}', - '\t\t Best practices: ${globals.hotfixDocumentationBestPractices}', - '\t 2. Post announcement to flutter-announce group', - '\t\t Flutter Announce: ${globals.flutterAnnounceGroup}', - '\t 3. Post announcement to discord and press the publish button', - '\t\t Discord: ${globals.discordReleaseChannel}', - '\t 4. Post announcement flutter release hotline chat room', - '\t\t Chatroom: ${globals.flutterReleaseHotline}', -"""; -// The helper functions in `state.dart` wrap the code-generated dart files in -// `lib/src/proto/`. The most interesting of these functions is: - -// * `pb.ConductorState readStateFromFile(File)` - uses the code generated -// `.mergeFromProto3Json()` method to deserialize the JSON content from the -// config file into a Dart instance of the `ConductorState` class. -// * `void writeStateFromFile(File, pb.ConductorState, List)` -// - similarly calls the `.toProto3Json()` method to serialize a -// * `ConductorState` instance to a JSON string which is then written to disk. -// `String phaseInstructions(pb.ConductorState state)` - returns instructions -// for what the user is supposed to do next based on `state.currentPhase`. -// * `String presentState(pb.ConductorState state)` - pretty print the state file. -// This is a little easier to read than the raw JSON. - -String luciConsoleLink(String candidateBranch, String repoName) { - assert( - globals.releaseCandidateBranchRegex.hasMatch(candidateBranch), - 'Malformed candidateBranch argument passed: "$candidateBranch"', - ); - assert( - ['flutter', 'engine', 'packaging'].contains(repoName), - 'group named $repoName not recognized', - ); - if (repoName == 'packaging') { - return 'https://luci-milo.appspot.com/p/dart-internal/g/flutter_packaging/console'; - } - return 'https://flutter-dashboard.appspot.com/#/build?repo=$repoName&branch=$candidateBranch'; -} - -String defaultStateFilePath(Platform platform) { - final String? home = platform.environment['HOME']; - if (home == null) { - throw globals.ConductorException(r'Environment variable $HOME must be set!'); - } - return [home, kStateFileName].join(platform.pathSeparator); -} - -String presentState(pb.ConductorState state) { - final StringBuffer buffer = StringBuffer(); - buffer.writeln('Conductor version: ${state.conductorVersion}'); - buffer.writeln('Release channel: ${state.releaseChannel}'); - buffer.writeln('Release version: ${state.releaseVersion}'); - buffer.writeln(); - buffer.writeln( - 'Release started at: ${DateTime.fromMillisecondsSinceEpoch(state.createdDate.toInt())}', - ); - buffer.writeln( - 'Last updated at: ${DateTime.fromMillisecondsSinceEpoch(state.lastUpdatedDate.toInt())}', - ); - buffer.writeln('Framework Repo'); - buffer.writeln('\tCandidate branch: ${state.framework.candidateBranch}'); - buffer.writeln('\tStarting git HEAD: ${state.framework.startingGitHead}'); - buffer.writeln('\tCurrent git HEAD: ${state.framework.currentGitHead}'); - buffer.writeln('\tPath to checkout: ${state.framework.checkoutPath}'); - buffer.writeln( - '\tPost-submit LUCI dashboard: ${luciConsoleLink(state.framework.candidateBranch, 'flutter')}', - ); - if (state.framework.cherrypicks.isNotEmpty) { - buffer.writeln('${state.framework.cherrypicks.length} Framework Cherrypicks:'); - for (final pb.Cherrypick cherrypick in state.framework.cherrypicks) { - buffer.writeln('\t${cherrypick.trunkRevision} - ${cherrypick.state}'); - } - } else { - buffer.writeln('0 Framework cherrypicks.'); - } - if (state.framework.dartRevision.isNotEmpty) { - buffer.writeln('New Dart SDK revision: ${state.engine.dartRevision}'); - } - buffer.writeln(); - if (state.currentPhase == ReleasePhase.VERIFY_RELEASE) { - buffer.writeln( - '${state.releaseChannel} release ${state.releaseVersion} has been published and verified.\n', - ); - return buffer.toString(); - } - buffer.writeln('The current phase is:'); - buffer.writeln(presentPhases(state.currentPhase)); - - buffer.writeln(phaseInstructions(state)); - buffer.writeln(); - buffer.writeln('Issue `conductor next` when you are ready to proceed.'); - return buffer.toString(); -} - -String presentPhases(ReleasePhase currentPhase) { - final StringBuffer buffer = StringBuffer(); - bool phaseCompleted = true; - - for (final ReleasePhase phase in ReleasePhase.values) { - if (phase == currentPhase) { - // This phase will execute the next time `conductor next` is run. - buffer.writeln('> ${phase.name} (current)'); - phaseCompleted = false; - } else if (phaseCompleted) { - // This phase was already completed. - buffer.writeln('✓ ${phase.name}'); - } else { - // This phase has not been completed yet. - buffer.writeln(' ${phase.name}'); - } - } - return buffer.toString(); -} - -String phaseInstructions(pb.ConductorState state) { - switch (state.currentPhase) { - case ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS: - final List outstandingCherrypicks = - state.framework.cherrypicks.where((pb.Cherrypick cp) { - return cp.state == pb.CherrypickState.PENDING || - cp.state == pb.CherrypickState.PENDING_WITH_CONFLICT; - }).toList(); - if (outstandingCherrypicks.isNotEmpty) { - return [ - 'You must now manually apply the following framework cherrypicks to the checkout', - 'at ${state.framework.checkoutPath} in order:', - for (final pb.Cherrypick cherrypick in outstandingCherrypicks) - '\t${cherrypick.trunkRevision}', - ].join('\n'); - } - return [ - 'Either all cherrypicks have been auto-applied or there were none.', - ].join('\n'); - case ReleasePhase.UPDATE_ENGINE_VERSION: - return 'The conductor will now update the engine.version file to point at the previous commit.'; - case ReleasePhase.PUBLISH_VERSION: - if (!requiresFrameworkPR(state)) { - return 'Since there are no code changes in this release, no Framework ' - 'PR is necessary.'; - } - - final String newPrLink = globals.getNewPrLink( - userName: githubAccount(state.framework.mirror.url), - repoName: 'flutter', - state: state, - ); - return [ - 'Your working branch ${state.framework.workingBranch} was pushed to your mirror.', - 'You must now open a pull request at $newPrLink', - 'verify pre-submit CI builds on your pull request are successful, merge your ', - 'pull request, validate post-submit CI.', - ].join('\n'); - case ReleasePhase.VERIFY_RELEASE: - return 'Release archive packages must be verified on cloud storage: ${luciConsoleLink(state.framework.candidateBranch, 'packaging')}'; - case ReleasePhase.RELEASE_COMPLETED: - if (state.releaseChannel == 'beta') { - return [ - betaPostReleaseMsg, - '-----------------------------------------------------------------------', - 'This release has been completed.', - ].join('\n'); - } - return [ - stablePostReleaseMsg, - '-----------------------------------------------------------------------', - 'This release has been completed.', - ].join('\n'); - } - // For analyzer - throw globals.ConductorException('Unimplemented phase ${state.currentPhase}'); -} - -/// Regex pattern for git remote host URLs. -/// -/// First group = git host (currently must be github.com) -/// Second group = account name -/// Third group = repo name -final RegExp githubRemotePattern = RegExp( - r'^(git@github\.com:|https?:\/\/github\.com\/)([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_-]+)(\.git)?$', -); - -/// Parses a Git remote URL and returns the account name. -/// -/// Uses [githubRemotePattern]. -String githubAccount(String remoteUrl) { - final String engineUrl = remoteUrl; - final RegExpMatch? match = githubRemotePattern.firstMatch(engineUrl); - if (match == null) { - throw globals.ConductorException('Cannot determine the GitHub account from $engineUrl'); - } - final String? accountName = match.group(2); - if (accountName == null || accountName.isEmpty) { - throw globals.ConductorException('Cannot determine the GitHub account from $match'); - } - return accountName; -} - -/// Returns the next phase in the ReleasePhase enum. -/// -/// Will throw a [ConductorException] if [ReleasePhase.RELEASE_COMPLETED] is -/// passed as an argument, as there is no next phase. -ReleasePhase getNextPhase(ReleasePhase currentPhase) { - final ReleasePhase? nextPhase = ReleasePhase.valueOf(currentPhase.value + 1); - if (nextPhase != null) { - return nextPhase; - } - throw globals.ConductorException('There is no next ReleasePhase after $currentPhase!'); -} - -// Indent two spaces. -const JsonEncoder _encoder = JsonEncoder.withIndent(' '); - -void writeStateToFile(File file, pb.ConductorState state, List logs) { - state.logs.addAll(logs); - file.writeAsStringSync(_encoder.convert(state.toProto3Json()), flush: true); -} - -pb.ConductorState readStateFromFile(File file) { - final pb.ConductorState state = pb.ConductorState(); - final String stateAsString = file.readAsStringSync(); - state.mergeFromProto3Json(jsonDecode(stateAsString)); - return state; -} - -/// This release will require a new Engine PR. -/// -/// The logic is if there are engine cherrypicks that have not been abandoned OR -/// there is a new Dart revision, then return true, else false. -bool requiresEnginePR(pb.ConductorState state) { - final bool hasRequiredCherrypicks = state.engine.cherrypicks.any( - (pb.Cherrypick cp) => cp.state != pb.CherrypickState.ABANDONED, - ); - if (hasRequiredCherrypicks) { - return true; - } - return state.engine.dartRevision.isNotEmpty; -} - -/// This release will require a new Framework PR. -/// -/// The logic is if there was an Engine PR OR there are framework cherrypicks -/// that have not been abandoned. -bool requiresFrameworkPR(pb.ConductorState state) { - if (requiresEnginePR(state)) { - return true; - } - final bool hasRequiredCherrypicks = state.framework.cherrypicks.any( - (pb.Cherrypick cp) => cp.state != pb.CherrypickState.ABANDONED, - ); - if (hasRequiredCherrypicks) { - return true; - } - return false; -} diff --git a/dev/conductor/core/lib/src/status.dart b/dev/conductor/core/lib/src/status.dart deleted file mode 100644 index 58a1f02b81735..0000000000000 --- a/dev/conductor/core/lib/src/status.dart +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/command_runner.dart'; -import 'package:file/file.dart'; -import 'package:platform/platform.dart'; - -import './proto/conductor_state.pb.dart' as pb; -import './repository.dart'; -import './state.dart'; -import './stdio.dart'; - -const String kVerboseFlag = 'verbose'; -const String kStateOption = 'state-file'; - -/// Command to print the status of the current Flutter release. -class StatusCommand extends Command { - StatusCommand({required this.checkouts}) - : platform = checkouts.platform, - fileSystem = checkouts.fileSystem, - stdio = checkouts.stdio { - final String defaultPath = defaultStateFilePath(platform); - argParser.addOption( - kStateOption, - defaultsTo: defaultPath, - help: 'Path to persistent state file. Defaults to $defaultPath', - ); - argParser.addFlag(kVerboseFlag, abbr: 'v', help: 'Also print logs.'); - } - - final Checkouts checkouts; - final FileSystem fileSystem; - final Platform platform; - final Stdio stdio; - - @override - String get name => 'status'; - - @override - String get description => 'Print status of current release.'; - - @override - void run() { - final File stateFile = checkouts.fileSystem.file(argResults![kStateOption]); - if (!stateFile.existsSync()) { - stdio.printStatus('No persistent state file found at ${argResults![kStateOption]}.'); - return; - } - final pb.ConductorState state = readStateFromFile(stateFile); - - stdio.printStatus(presentState(state)); - if (argResults![kVerboseFlag] as bool) { - stdio.printStatus('\nLogs:'); - state.logs.forEach(stdio.printStatus); - } - } -} diff --git a/dev/conductor/core/lib/src/version.dart b/dev/conductor/core/lib/src/version.dart index 8aa3f10cbba0a..11ef3f64d0825 100644 --- a/dev/conductor/core/lib/src/version.dart +++ b/dev/conductor/core/lib/src/version.dart @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'globals.dart' show ConductorException, releaseCandidateBranchRegex; - -import 'proto/conductor_state.pbenum.dart'; +import 'globals.dart' show ConductorException; /// Possible string formats that `flutter --version` can return. enum VersionType { @@ -222,50 +220,6 @@ class Version { final VersionType type; - /// Validate that the parsed version is valid. - /// - /// Will throw a [ConductorException] if the version is not possible given the - /// [candidateBranch] and [incrementLetter]. - void ensureValid(String candidateBranch, ReleaseType releaseType) { - final RegExpMatch? branchMatch = releaseCandidateBranchRegex.firstMatch(candidateBranch); - if (branchMatch == null) { - throw ConductorException( - 'Candidate branch $candidateBranch does not match the pattern ' - '${releaseCandidateBranchRegex.pattern}', - ); - } - - // These groups are required in the pattern, so these match groups should - // not be null - final String branchX = branchMatch.group(1)!; - if (x != int.tryParse(branchX)) { - throw ConductorException( - 'Parsed version $this has a different x value than candidate ' - 'branch $candidateBranch', - ); - } - final String branchY = branchMatch.group(2)!; - if (y != int.tryParse(branchY)) { - throw ConductorException( - 'Parsed version $this has a different y value than candidate ' - 'branch $candidateBranch', - ); - } - - // stable type versions don't have an m field set - if (type != VersionType.stable && - releaseType != ReleaseType.STABLE_HOTFIX && - releaseType != ReleaseType.STABLE_INITIAL) { - final String branchM = branchMatch.group(3)!; - if (m != int.tryParse(branchM)) { - throw ConductorException( - 'Parsed version $this has a different m value than candidate ' - 'branch $candidateBranch with type $type', - ); - } - } - } - @override String toString() { return switch (type) { diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 12ff2aeb88815..d78519417c872 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -6,66 +6,21 @@ publish_to: none environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - archive: 3.6.1 - args: 2.7.0 - http: 1.4.0 - intl: 0.20.2 - meta: 1.16.0 - path: 1.9.1 - process: 5.0.3 - protobuf: 4.1.0 + args: any + meta: any + path: any + process: any + protobuf: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fixnum: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: any + fixnum: any + platform: any dev_dependencies: - test: 1.26.1 - test_api: 0.7.6 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: dcc6 +# PUBSPEC CHECKSUM: 1p5qu diff --git a/dev/conductor/core/test/candidates_test.dart b/dev/conductor/core/test/candidates_test.dart deleted file mode 100644 index dee7aa36b03ef..0000000000000 --- a/dev/conductor/core/test/candidates_test.dart +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/candidates.dart'; -import 'package:conductor_core/src/repository.dart'; -import 'package:file/memory.dart'; -import 'package:platform/platform.dart'; - -import './common.dart'; - -void main() { - group( - 'candidates command', - () { - const String flutterRoot = '/flutter'; - const String flutterBinPath = '$flutterRoot/bin/flutter'; - const String checkoutsParentDirectory = '$flutterRoot/dev/tools/'; - const String remoteName = 'origin'; - - late MemoryFileSystem fileSystem; - late FakePlatform platform; - late TestStdio stdio; - late FakeProcessManager processManager; - final String operatingSystem = const LocalPlatform().operatingSystem; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - }); - - CommandRunner createRunner({required Checkouts checkouts}) { - final CandidatesCommand command = CandidatesCommand( - checkouts: checkouts, - flutterRoot: fileSystem.directory(flutterRoot), - ); - return CommandRunner('clean-test', '')..addCommand(command); - } - - test('prints only branches from targeted remote', () async { - const String currentVersion = '1.2.3'; - const String branch = 'flutter-1.3-candidate.0'; - - processManager = FakeProcessManager.list([ - const FakeCommand(command: ['git', 'fetch', remoteName]), - const FakeCommand(command: [flutterBinPath, 'help']), - const FakeCommand( - command: [flutterBinPath, '--version', '--machine'], - stdout: '{"frameworkVersion": "$currentVersion"}', - ), - FakeCommand( - command: const [ - 'git', - 'branch', - '--no-color', - '--remotes', - '--list', - '$remoteName/*', - ], - stdout: [ - 'other-remote/flutter-5.0-candidate.0', - '$remoteName/$branch', - ].join('\n'), - ), - ]); - final String pathSeparator = operatingSystem == 'windows' ? r'\' : '/'; - - platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(pathSeparator), - }, - pathSeparator: pathSeparator, - ); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['candidates', '--$kRemote', remoteName]); - expect(stdio.stdout.contains('currentVersion = $currentVersion'), true); - expect(stdio.stdout.contains(branch), true); - expect(stdio.stdout.contains('flutter-5.0-candidate.0'), false); - }); - - test('does not print branches older or equal to current version', () async { - const String currentVersion = '2.3.0-13.0.pre.48'; - const String newBranch = 'flutter-2.4-candidate.0'; - const String oldBranch = 'flutter-1.0-candidate.0'; - const String currentBranch = 'flutter-2.3-candidate.13'; - - processManager = FakeProcessManager.list([ - const FakeCommand(command: ['git', 'fetch', remoteName]), - const FakeCommand(command: [flutterBinPath, 'help']), - const FakeCommand( - command: [flutterBinPath, '--version', '--machine'], - stdout: '{"frameworkVersion": "$currentVersion"}', - ), - FakeCommand( - command: const [ - 'git', - 'branch', - '--no-color', - '--remotes', - '--list', - '$remoteName/*', - ], - stdout: [ - '$remoteName/$oldBranch', - '$remoteName/$currentBranch', - '$remoteName/$newBranch', - ].join('\n'), - ), - ]); - final String pathSeparator = operatingSystem == 'windows' ? r'\' : '/'; - - platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(pathSeparator), - }, - pathSeparator: pathSeparator, - ); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['candidates', '--$kRemote', remoteName]); - expect(stdio.stdout.contains('currentVersion = $currentVersion'), true); - expect(stdio.stdout.contains(newBranch), true); - expect(stdio.stdout.contains(oldBranch), false); - expect(stdio.stdout.contains(currentBranch), false); - }); - }, - onPlatform: { - 'windows': const Skip('Flutter Conductor only supported on macos/linux'), - }, - ); -} diff --git a/dev/conductor/core/test/clean_test.dart b/dev/conductor/core/test/clean_test.dart deleted file mode 100644 index e9bb1d1d3ee9c..0000000000000 --- a/dev/conductor/core/test/clean_test.dart +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/clean.dart'; -import 'package:conductor_core/src/repository.dart'; -import 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:platform/platform.dart'; - -import './common.dart'; - -void main() { - group( - 'clean command', - () { - const String flutterRoot = '/flutter'; - const String checkoutsParentDirectory = '$flutterRoot/dev/tools/'; - const String stateFilePath = '/state-file.json'; - - late MemoryFileSystem fileSystem; - late FakePlatform platform; - late TestStdio stdio; - late FakeProcessManager processManager; - late CommandRunner runner; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - final String operatingSystem = const LocalPlatform().operatingSystem; - final String pathSeparator = operatingSystem == 'windows' ? r'\' : '/'; - - processManager = FakeProcessManager.empty(); - platform = FakePlatform( - environment: {'HOME': '/path/to/user/home'}, - pathSeparator: pathSeparator, - ); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CleanCommand command = CleanCommand(checkouts: checkouts); - runner = CommandRunner('clean-test', '')..addCommand(command); - }); - - test('throws if no state file found', () async { - await expectLater( - () async => - runner.run(['clean', '--$kStateOption', stateFilePath, '--$kYesFlag']), - throwsExceptionWith('No persistent state file found at $stateFilePath'), - ); - }); - - test('deletes an empty state file', () async { - final File stateFile = fileSystem.file(stateFilePath); - stateFile.writeAsStringSync(''); - - await runner.run(['clean', '--$kStateOption', stateFile.path, '--$kYesFlag']); - - expect(stateFile.existsSync(), false); - }); - - test('deletes a state file with content', () async { - final File stateFile = fileSystem.file(stateFilePath); - stateFile.writeAsStringSync('{status: pending}'); - - await runner.run(['clean', '--$kStateOption', stateFile.path, '--$kYesFlag']); - - expect(stateFile.existsSync(), false); - }); - }, - onPlatform: { - 'windows': const Skip('Flutter Conductor only supported on macos/linux'), - }, - ); -} diff --git a/dev/conductor/core/test/globals_test.dart b/dev/conductor/core/test/globals_test.dart deleted file mode 100644 index 8d18d04f13580..0000000000000 --- a/dev/conductor/core/test/globals_test.dart +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/args.dart'; -import 'package:conductor_core/src/globals.dart'; -import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; - -import './common.dart'; - -void main() { - test('assertsEnabled returns true in test suite', () { - expect(assertsEnabled(), true); - }); - - group('getNewPrLink', () { - const String userName = 'flutterer'; - const String releaseChannel = 'beta'; - const String releaseVersion = '1.2.0-3.4.pre'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - const String workingBranch = 'cherrypicks-$candidateBranch'; - const String dartRevision = 'fe9708ab688dcda9923f584ba370a66fcbc3811f'; - const String engineCherrypick1 = 'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'; - const String engineCherrypick2 = '94d06a2e1d01a3b0c693b94d70c5e1df9d78d249'; - const String frameworkCherrypick = 'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'; - - final RegExp titlePattern = RegExp(r'&title=(.*)&'); - final RegExp bodyPattern = RegExp(r'&body=(.*)$'); - - late pb.ConductorState state; - - setUp(() { - state = - (pb.ConductorState.create() - ..engine = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..cherrypicks.addAll([ - pb.Cherrypick.create()..trunkRevision = engineCherrypick1, - pb.Cherrypick.create()..trunkRevision = engineCherrypick2, - ]) - ..dartRevision = dartRevision - ..workingBranch = workingBranch) - ..framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..cherrypicks.add(pb.Cherrypick.create()..trunkRevision = frameworkCherrypick) - ..workingBranch = workingBranch) - ..releaseChannel = releaseChannel - ..releaseVersion = releaseVersion); - }); - - test('throws on an invalid repoName', () { - expect( - () => getNewPrLink(repoName: 'flooter', userName: userName, state: state), - throwsExceptionWith('Expected repoName to be one of flutter or engine but got flooter.'), - ); - }); - - test('returns a valid URL for engine', () { - final String link = getNewPrLink(repoName: 'engine', userName: userName, state: state); - expect(link, contains('https://github.com/flutter/engine/compare/')); - expect(link, contains('$candidateBranch...$userName:$workingBranch?expand=1')); - expect( - Uri.decodeQueryComponent(titlePattern.firstMatch(link)?.group(1) ?? ''), - '[flutter_releases] Flutter $releaseChannel $releaseVersion Engine Cherrypicks', - ); - final String expectedBody = ''' -# Flutter $releaseChannel $releaseVersion Engine - -## Scheduled Cherrypicks - -- Roll dart revision: dart-lang/sdk@${dartRevision.substring(0, 9)} -- commit: flutter/engine@${engineCherrypick1.substring(0, 9)} -- commit: flutter/engine@${engineCherrypick2.substring(0, 9)} -'''; - expect(Uri.decodeQueryComponent(bodyPattern.firstMatch(link)?.group(1) ?? ''), expectedBody); - }); - - test('returns a valid URL for framework', () { - final String link = getNewPrLink(repoName: 'flutter', userName: userName, state: state); - expect(link, contains('https://github.com/flutter/flutter/compare/')); - expect(link, contains('$candidateBranch...$userName:$workingBranch?expand=1')); - expect( - Uri.decodeQueryComponent(titlePattern.firstMatch(link)?.group(1) ?? ''), - '[flutter_releases] Flutter $releaseChannel $releaseVersion Framework Cherrypicks', - ); - final String expectedBody = ''' -# Flutter $releaseChannel $releaseVersion Framework - -## Scheduled Cherrypicks - -- commit: ${frameworkCherrypick.substring(0, 9)} -'''; - expect(Uri.decodeQueryComponent(bodyPattern.firstMatch(link)?.group(1) ?? ''), expectedBody); - }); - }); - - group('getBoolFromEnvOrArgs', () { - const String flagName = 'a-cli-flag'; - - test('prefers env over argResults', () { - final ArgResults argResults = FakeArgs(results: {flagName: false}); - final Map env = {'A_CLI_FLAG': 'TRUE'}; - final bool result = getBoolFromEnvOrArgs(flagName, argResults, env); - expect(result, true); - }); - - test('falls back to argResults if env is empty', () { - final ArgResults argResults = FakeArgs(results: {flagName: false}); - final Map env = {}; - final bool result = getBoolFromEnvOrArgs(flagName, argResults, env); - expect(result, false); - }); - }); -} - -class FakeArgs extends Fake implements ArgResults { - FakeArgs({ - this.arguments = const [], - this.name = 'fake-command', - this.results = const {}, - }); - - final Map results; - - @override - final List arguments; - - @override - final String name; - - @override - bool wasParsed(String name) { - return results[name] != null; - } - - @override - Object? operator [](String name) { - return results[name]; - } -} diff --git a/dev/conductor/core/test/next_test.dart b/dev/conductor/core/test/next_test.dart deleted file mode 100644 index 0f5dea8878e38..0000000000000 --- a/dev/conductor/core/test/next_test.dart +++ /dev/null @@ -1,625 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/git.dart'; -import 'package:conductor_core/src/globals.dart'; -import 'package:conductor_core/src/next.dart'; -import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; -import 'package:conductor_core/src/proto/conductor_state.pbenum.dart' show ReleasePhase; -import 'package:conductor_core/src/repository.dart'; -import 'package:conductor_core/src/state.dart'; -import 'package:conductor_core/src/stdio.dart'; -import 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:platform/platform.dart'; - -import './common.dart'; - -void main() { - const String flutterRoot = '/flutter'; - const String checkoutsParentDirectory = '$flutterRoot/dev/conductor'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - const String workingBranch = 'cherrypicks-$candidateBranch'; - const String revision1 = 'd3af60d18e01fcb36e0c0fa06c8502e4935ed095'; - const String revision2 = 'ffffffffffffffffffffffffffffffffffffffff'; - const String releaseVersion = '1.2.0-3.0.pre'; - const String releaseChannel = 'beta'; - const String stateFile = '/state-file.json'; - final String localPathSeparator = const LocalPlatform().pathSeparator; - final String localOperatingSystem = const LocalPlatform().operatingSystem; - - group( - 'next command', - () { - late MemoryFileSystem fileSystem; - late TestStdio stdio; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - }); - - CommandRunner createRunner({required Checkouts checkouts}) { - final NextCommand command = NextCommand(checkouts: checkouts); - return CommandRunner('codesign-test', '')..addCommand(command); - } - - test('throws if no state file found', () async { - final FakeProcessManager processManager = FakeProcessManager.list([]); - final FakePlatform platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(localPathSeparator), - }, - operatingSystem: localOperatingSystem, - pathSeparator: localPathSeparator, - ); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CommandRunner runner = createRunner(checkouts: checkouts); - expect( - () async => runner.run(['next', '--$kStateOption', stateFile]), - throwsExceptionWith('No persistent state file found at $stateFile'), - ); - }); - - group('APPLY_FRAMEWORK_CHERRYPICKS to UPDATE_ENGINE_VERSION', () { - const String mirrorRemoteUrl = 'https://github.com/org/repo.git'; - const String upstreamRemoteUrl = 'https://github.com/mirror/repo.git'; - const String engineUpstreamRemoteUrl = 'https://github.com/mirror/engine.git'; - const String frameworkCheckoutPath = '$checkoutsParentDirectory/framework'; - const String engineCheckoutPath = '$checkoutsParentDirectory/engine'; - const String oldEngineVersion = '000000001'; - const String frameworkCherrypick = '431ae69b4dd2dd48f7ba0153671e0311014c958b'; - late FakeProcessManager processManager; - late FakePlatform platform; - late pb.ConductorState state; - - setUp(() { - processManager = FakeProcessManager.empty(); - platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(localPathSeparator), - }, - operatingSystem: localOperatingSystem, - pathSeparator: localPathSeparator, - ); - state = - (pb.ConductorState.create() - ..releaseChannel = releaseChannel - ..releaseVersion = releaseVersion - ..framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..checkoutPath = frameworkCheckoutPath - ..cherrypicks.add( - pb.Cherrypick.create() - ..trunkRevision = frameworkCherrypick - ..state = pb.CherrypickState.PENDING, - ) - ..mirror = - (pb.Remote.create() - ..name = 'mirror' - ..url = mirrorRemoteUrl) - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = upstreamRemoteUrl) - ..workingBranch = workingBranch) - ..engine = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..checkoutPath = engineCheckoutPath - ..dartRevision = 'cdef0123' - ..workingBranch = workingBranch - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = engineUpstreamRemoteUrl)) - ..currentPhase = ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS); - // create engine repo - fileSystem.directory(engineCheckoutPath).createSync(recursive: true); - // create framework repo - final Directory frameworkDir = fileSystem.directory(frameworkCheckoutPath); - final File engineRevisionFile = frameworkDir - .childDirectory('bin') - .childDirectory('internal') - .childFile('engine.version'); - engineRevisionFile.createSync(recursive: true); - engineRevisionFile.writeAsStringSync(oldEngineVersion, flush: true); - }); - - test('does not update state.currentPhase if user responds no', () async { - stdio.stdin.add('n'); - processManager.addCommands([ - const FakeCommand(command: ['git', 'fetch', 'upstream']), - const FakeCommand(command: ['git', 'checkout', workingBranch]), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM bin/internal/release-candidate-branch.version', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: [ - 'git', - 'commit', - '--message', - 'Create candidate branch version $candidateBranch for $releaseChannel', - ], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - ]); - writeStateToFile(fileSystem.file(stateFile), state, []); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['next', '--$kStateOption', stateFile]); - - final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile)); - - expect(processManager, hasNoRemainingExpectations); - expect( - stdio.stdout, - contains( - 'Are you ready to push your framework branch to the repository $mirrorRemoteUrl? (y/n) ', - ), - ); - expect(stdio.error, contains('Aborting command.')); - expect(finalState.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS); - }); - - test('updates state.currentPhase if user responds yes', () async { - stdio.stdin.add('y'); - processManager.addCommands([ - // Engine repo - const FakeCommand(command: ['git', 'fetch', 'upstream']), - FakeCommand( - command: const ['git', 'checkout', workingBranch], - onRun: (_) { - final File file = fileSystem.file('$checkoutsParentDirectory/framework/.ci.yaml') - ..createSync(); - _initializeCiYamlFile(file); - }, - ), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM bin/internal/release-candidate-branch.version', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: [ - 'git', - 'commit', - '--message', - 'Create candidate branch version $candidateBranch for $releaseChannel', - ], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - const FakeCommand( - command: ['git', 'push', 'mirror', 'HEAD:refs/heads/$workingBranch'], - ), - ]); - writeStateToFile(fileSystem.file(stateFile), state, []); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['next', '--$kStateOption', stateFile]); - - final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile)); - - expect(finalState.currentPhase, ReleasePhase.UPDATE_ENGINE_VERSION); - expect(stdio.stdout, contains('There was 1 cherrypick that was not auto-applied')); - expect( - stdio.stdout, - contains( - 'Are you ready to push your framework branch to the repository $mirrorRemoteUrl? (y/n)', - ), - ); - expect( - stdio.stdout, - contains('Executed command: `git push mirror HEAD:refs/heads/$workingBranch`'), - ); - expect(stdio.error, isEmpty); - }); - }); - group('UPDATE_ENGINE_VERSION to PUBLISH_VERSION', () { - const String mirrorRemoteUrl = 'https://github.com/org/repo.git'; - const String upstreamRemoteUrl = 'https://github.com/mirror/repo.git'; - const String engineUpstreamRemoteUrl = 'https://github.com/mirror/engine.git'; - const String frameworkCheckoutPath = '$checkoutsParentDirectory/framework'; - const String engineCheckoutPath = '$checkoutsParentDirectory/engine'; - const String oldEngineVersion = '000000001'; - - late FakeProcessManager processManager; - late FakePlatform platform; - late pb.ConductorState state; - - setUp(() { - processManager = FakeProcessManager.empty(); - platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(localPathSeparator), - }, - operatingSystem: localOperatingSystem, - pathSeparator: localPathSeparator, - ); - state = - (pb.ConductorState.create() - ..releaseChannel = releaseChannel - ..releaseVersion = releaseVersion - ..framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..checkoutPath = frameworkCheckoutPath - ..mirror = - (pb.Remote.create() - ..name = 'mirror' - ..url = mirrorRemoteUrl) - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = upstreamRemoteUrl) - ..workingBranch = workingBranch) - ..engine = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..checkoutPath = engineCheckoutPath - ..dartRevision = 'cdef0123' - ..workingBranch = workingBranch - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = engineUpstreamRemoteUrl)) - ..currentPhase = ReleasePhase.UPDATE_ENGINE_VERSION); - // create engine repo - fileSystem.directory(engineCheckoutPath).createSync(recursive: true); - // create framework repo - final Directory frameworkDir = fileSystem.directory(frameworkCheckoutPath); - final File engineRevisionFile = frameworkDir - .childDirectory('bin') - .childDirectory('internal') - .childFile('engine.version'); - engineRevisionFile.createSync(recursive: true); - engineRevisionFile.writeAsStringSync(oldEngineVersion, flush: true); - }); - - test('creates a PR with an updated engine.version file', () async { - // Respond "yes" to the prompt to push branch - stdio.stdin.add('y'); - processManager.addCommands(const [ - FakeCommand(command: ['git', 'fetch', 'upstream']), - FakeCommand(command: ['git', 'checkout', 'cherrypicks-$candidateBranch']), - FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision1), - FakeCommand(command: ['git', 'add', 'bin/internal/engine.version', '--force']), - FakeCommand( - command: [ - 'git', - 'commit', - '--message', - 'Create engine.version file pointing to $revision1', - ], - ), - FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - FakeCommand( - command: [ - 'git', - 'push', - 'mirror', - 'HEAD:refs/heads/cherrypicks-$candidateBranch', - ], - ), - ]); - writeStateToFile(fileSystem.file(stateFile), state, []); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['next', '--$kStateOption', stateFile]); - - final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile)); - - expect(finalState.currentPhase, ReleasePhase.PUBLISH_VERSION); - expect( - fileSystem - .file('$frameworkCheckoutPath/bin/internal/engine.version') - .readAsStringSync(), - revision1, - ); - }); - }); - - group('PUBLISH_VERSION to VERIFY_RELEASE', () { - const String releaseVersion = '1.2.0-3.0.pre'; - late pb.ConductorState state; - - setUp(() { - state = - (pb.ConductorState.create() - ..releaseChannel = releaseChannel - ..currentPhase = ReleasePhase.PUBLISH_VERSION - ..framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..upstream = (pb.Remote.create()..url = FrameworkRepository.defaultUpstream)) - ..releaseVersion = releaseVersion); - }); - - test('gives push command and updates state.currentPhase', () async { - stdio.stdin.add('y'); - final FakeProcessManager processManager = FakeProcessManager.empty(); - final FakePlatform platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(localPathSeparator), - }, - operatingSystem: localOperatingSystem, - pathSeparator: localPathSeparator, - ); - writeStateToFile(fileSystem.file(stateFile), state, []); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CommandRunner runner = createRunner(checkouts: checkouts); - await runner.run(['next', '--$kStateOption', stateFile]); - - final pb.ConductorState finalState = readStateFromFile(fileSystem.file(stateFile)); - - expect(processManager, hasNoRemainingExpectations); - expect(finalState.currentPhase, ReleasePhase.VERIFY_RELEASE); - expect(stdio.stdout, contains('Run the following command, and ask a Googler')); - expect(stdio.stdout, contains(':tag $releaseVersion')); - expect(stdio.stdout, contains(':git_branch ${state.framework.candidateBranch}')); - expect(stdio.stdout, contains(':release_channel ${state.releaseChannel}')); - expect(finalState.logs, stdio.logs); - }); - }); - - test('throws exception if state.currentPhase is RELEASE_COMPLETED', () async { - final FakeProcessManager processManager = FakeProcessManager.empty(); - final FakePlatform platform = FakePlatform( - environment: { - 'HOME': ['path', 'to', 'home'].join(localPathSeparator), - }, - operatingSystem: localOperatingSystem, - pathSeparator: localPathSeparator, - ); - final pb.ConductorState state = - pb.ConductorState.create()..currentPhase = ReleasePhase.RELEASE_COMPLETED; - writeStateToFile(fileSystem.file(stateFile), state, []); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final CommandRunner runner = createRunner(checkouts: checkouts); - expect( - () async => runner.run(['next', '--$kStateOption', stateFile]), - throwsExceptionWith('This release is finished.'), - ); - }); - }, - onPlatform: { - 'windows': const Skip('Flutter Conductor only supported on macos/linux'), - }, - ); - - group('prompt', () { - test('can be overridden for different frontend implementations', () async { - final FileSystem fileSystem = MemoryFileSystem.test(); - final Stdio stdio = _UnimplementedStdio.instance; - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory('/'), - platform: FakePlatform(), - processManager: FakeProcessManager.empty(), - stdio: stdio, - ); - final _TestNextContext context = _TestNextContext( - checkouts: checkouts, - stateFile: fileSystem.file('/statefile.json'), - ); - - final bool response = await context.prompt('A prompt that will immediately be agreed to'); - expect(response, true); - }); - - test('throws if user inputs character that is not "y" or "n"', () { - final FileSystem fileSystem = MemoryFileSystem.test(); - final TestStdio stdio = TestStdio(stdin: ['x'], verbose: true); - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory('/'), - platform: FakePlatform(), - processManager: FakeProcessManager.empty(), - stdio: stdio, - ); - final NextContext context = NextContext( - autoAccept: false, - force: false, - checkouts: checkouts, - stateFile: fileSystem.file('/statefile.json'), - ); - - expect( - () => context.prompt('Asking a question?'), - throwsExceptionWith('Unknown user input (expected "y" or "n")'), - ); - }); - }); - - group('.pushWorkingBranch()', () { - late MemoryFileSystem fileSystem; - late TestStdio stdio; - late Platform platform; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - platform = FakePlatform(); - }); - - test( - 'catches GitException if the push was rejected and instead throws a helpful ConductorException', - () async { - const String gitPushErrorMessage = ''' - To github.com:user/engine.git - - ! [rejected] HEAD -> cherrypicks-flutter-2.8-candidate.3 (non-fast-forward) - error: failed to push some refs to 'github.com:user/engine.git' - hint: Updates were rejected because the tip of your current branch is behind - hint: its remote counterpart. Integrate the remote changes (e.g. - hint: 'git pull ...') before pushing again. - hint: See the 'Note about fast-forwards' in 'git push --help' for details. -'''; - final Checkouts checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory) - ..createSync(recursive: true), - platform: platform, - processManager: FakeProcessManager.empty(), - stdio: stdio, - ); - final Repository testRepository = _TestRepository.fromCheckouts(checkouts); - final pb.Repository testPbRepository = pb.Repository(); - (checkouts.processManager as FakeProcessManager).addCommands([ - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - testRepository.upstreamRemote.url, - '/flutter/dev/conductor/flutter_conductor_checkouts/test-repo/test-repo', - ], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision1), - FakeCommand( - command: const ['git', 'push', '', 'HEAD:refs/heads/'], - exception: GitException(gitPushErrorMessage, [ - 'git', - 'push', - '--force', - '', - 'HEAD:refs/heads/', - ]), - ), - ]); - final NextContext nextContext = NextContext( - autoAccept: false, - checkouts: checkouts, - force: false, - stateFile: fileSystem.file(stateFile), - ); - - expect( - () => nextContext.pushWorkingBranch(testRepository, testPbRepository), - throwsA( - isA().having( - (ConductorException exception) => exception.message, - 'has correct message', - contains('Re-run this command with --force to overwrite the remote branch'), - ), - ), - ); - }, - ); - }); -} - -/// A [Stdio] that will throw an exception if any of its methods are called. -class _UnimplementedStdio extends Fake implements Stdio { - _UnimplementedStdio(); - - static final _UnimplementedStdio instance = _UnimplementedStdio(); -} - -class _TestRepository extends Repository { - _TestRepository.fromCheckouts(Checkouts checkouts, [String name = 'test-repo']) - : super( - fileSystem: checkouts.fileSystem, - parentDirectory: checkouts.directory.childDirectory(name), - platform: checkouts.platform, - processManager: checkouts.processManager, - name: name, - requiredLocalBranches: [], - stdio: checkouts.stdio, - upstreamRemote: const Remote.upstream('git@github.com:upstream/repo.git'), - ); - - @override - Future<_TestRepository> cloneRepository(String? cloneName) async { - throw Exception('Unimplemented!'); - } -} - -class _TestNextContext extends NextContext { - const _TestNextContext({required super.stateFile, required super.checkouts}) - : super(autoAccept: false, force: false); - - @override - Future prompt(String message) { - // always say yes - return Future.value(true); - } -} - -void _initializeCiYamlFile(File file, {List? enabledBranches}) { - enabledBranches ??= ['master', 'beta', 'stable']; - file.createSync(recursive: true); - final StringBuffer buffer = StringBuffer('enabled_branches:\n'); - for (final String branch in enabledBranches) { - buffer.writeln(' - $branch'); - } - buffer.writeln(''' - -platform_properties: - linux: - properties: - caches: ["name":"openjdk","path":"java"] - -targets: - - name: Linux analyze - recipe: flutter/flutter - timeout: 60 - properties: - tags: > - ["framework","hostonly"] - validation: analyze - validation_name: Analyze - scheduler: luci -'''); - file.writeAsStringSync(buffer.toString()); -} diff --git a/dev/conductor/core/test/packages_autoroller_test.dart b/dev/conductor/core/test/packages_autoroller_test.dart index 88570fb1d6dbc..c9514284c153e 100644 --- a/dev/conductor/core/test/packages_autoroller_test.dart +++ b/dev/conductor/core/test/packages_autoroller_test.dart @@ -6,8 +6,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io' as io; -import 'package:conductor_core/conductor_core.dart'; import 'package:conductor_core/packages_autoroller.dart'; +import 'package:conductor_core/src/repository.dart'; +import 'package:conductor_core/src/stdio.dart'; import 'package:conductor_core/src/validate_checkout_post_gradle_regeneration.dart'; import 'package:file/memory.dart'; import 'package:path/path.dart' show Context, Style; @@ -252,7 +253,7 @@ void main() { const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: 'deadbeef'), const FakeCommand( command: [ - '$checkoutsParentDirectory/flutter_conductor_checkouts/framework/bin/dart', + '$checkoutsParentDirectory/flutter_conductor_checkouts/framework/bin/flutter', 'pub', 'get', ], @@ -344,7 +345,7 @@ void main() { const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: 'deadbeef'), const FakeCommand( command: [ - '$checkoutsParentDirectory/flutter_conductor_checkouts/framework/bin/dart', + '$checkoutsParentDirectory/flutter_conductor_checkouts/framework/bin/flutter', 'pub', 'get', ], diff --git a/dev/conductor/core/test/start_test.dart b/dev/conductor/core/test/start_test.dart deleted file mode 100644 index 22f04cae9446e..0000000000000 --- a/dev/conductor/core/test/start_test.dart +++ /dev/null @@ -1,741 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert' show jsonDecode; - -import 'package:args/command_runner.dart'; -import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; -import 'package:conductor_core/src/proto/conductor_state.pbenum.dart'; -import 'package:conductor_core/src/repository.dart'; -import 'package:conductor_core/src/start.dart'; -import 'package:conductor_core/src/state.dart'; -import 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:platform/platform.dart'; - -import './common.dart'; - -void main() { - group( - 'start command', - () { - const String branchPointRevision = '5131a6e5e0c50b8b7b2906cd58dab8746d6450be'; - const String flutterRoot = '/flutter'; - const String checkoutsParentDirectory = '$flutterRoot/dev/tools/'; - const String githubUsername = 'user'; - const String frameworkMirror = 'git@github.com:$githubUsername/flutter.git'; - const String candidateBranch = 'flutter-1.2-candidate.3'; - const String releaseChannel = 'beta'; - const String revision = 'abcd1234'; - const String conductorVersion = 'deadbeef'; - late Checkouts checkouts; - late MemoryFileSystem fileSystem; - late FakePlatform platform; - late TestStdio stdio; - late FakeProcessManager processManager; - - setUp(() { - stdio = TestStdio(); - fileSystem = MemoryFileSystem.test(); - }); - - CommandRunner createRunner({ - Map? environment, - String? operatingSystem, - List? commands, - }) { - operatingSystem ??= const LocalPlatform().operatingSystem; - final String pathSeparator = operatingSystem == 'windows' ? r'\' : '/'; - environment ??= {'HOME': '/path/to/user/home'}; - final Directory homeDir = fileSystem.directory(environment['HOME']); - // Tool assumes this exists - homeDir.createSync(recursive: true); - platform = FakePlatform( - environment: environment, - operatingSystem: operatingSystem, - pathSeparator: pathSeparator, - ); - processManager = FakeProcessManager.list(commands ?? []); - checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - final StartCommand command = StartCommand( - checkouts: checkouts, - conductorVersion: conductorVersion, - ); - return CommandRunner('codesign-test', '')..addCommand(command); - } - - group('start arg parser', () { - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - late StartCommand startCommand; - setUp(() { - final String operatingSystem = const LocalPlatform().operatingSystem; - final Map environment = {'HOME': '/path/to/user/home'}; - final Directory homeDir = fileSystem.directory(environment['HOME']); - // Tool assumes this exists - homeDir.createSync(recursive: true); - platform = FakePlatform( - environment: environment, - operatingSystem: operatingSystem, - pathSeparator: '/', - ); - processManager = FakeProcessManager.list([]); - checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - startCommand = StartCommand(checkouts: checkouts, conductorVersion: conductorVersion); - }); - - test('default args', () async { - final List args = [ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - 'stable', - '--$kStateOption', - '/path/to/statefile.json', - '--$kDartRevisionOption', - nextDartRevision, - '--$kGithubUsernameOption', - githubUsername, - ]; - final StartContext context = startCommand.createContext( - startCommand.argParser.parse(args), - ); - expect(context.frameworkUpstream, FrameworkRepository.defaultUpstream); - expect(context.frameworkMirror, contains(githubUsername)); - expect(context.frameworkMirror, contains('/flutter.git')); - }); - - test('overridden mirror', () async { - const String customFrameworkMirror = 'git@github.com:$githubUsername/flutter-work.git'; - final List args = [ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - 'stable', - '--$kStateOption', - '/path/to/statefile.json', - '--$kDartRevisionOption', - nextDartRevision, - '--$kGithubUsernameOption', - githubUsername, - '--$kFrameworkMirrorOption', - customFrameworkMirror, - ]; - final StartContext context = startCommand.createContext( - startCommand.argParser.parse(args), - ); - expect(context.frameworkMirror, customFrameworkMirror); - }); - }); - - test('throws exception if run from Windows', () async { - final CommandRunner runner = createRunner( - commands: [ - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision), - ], - operatingSystem: 'windows', - ); - await expectLater( - () async => runner.run([ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - 'beta', - '--$kStateOption', - '/path/to/statefile.json', - ]), - throwsExceptionWith('Error! This tool is only supported on macOS and Linux'), - ); - }); - - test('throws if provided an invalid --$kVersionOverrideOption', () async { - final CommandRunner runner = createRunner(); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - - await expectLater( - () async => runner.run([ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - releaseChannel, - '--$kStateOption', - stateFilePath, - '--$kVersionOverrideOption', - 'an invalid version string', - '--$kGithubUsernameOption', - githubUsername, - ]), - throwsExceptionWith('an invalid version string cannot be parsed'), - ); - }); - - test('creates state file if provided correct inputs', () async { - stdio.stdin.add('y'); // accept prompt from ensureBranchPointTagged() - const String revision2 = 'def789'; - const String revision3 = '123abc'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-1.0.pre'; - // This is what this release will be - const String nextVersion = '1.2.0-1.1.pre'; - const String candidateBranch = 'flutter-1.2-candidate.1'; - - final List commands = [ - // clone and rev-parse framework - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - FrameworkRepository.defaultUpstream, - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - ), - ], - onRun: (_) { - // ensure this is a monorepo checkout - fileSystem - .directory( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'engine', - ), - ) - .createSync(recursive: true); - fileSystem - .file( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'DEPS', - ), - ) - .writeAsStringSync(generateMockDeps(previousDartRevision)); - }, - ), - const FakeCommand(command: ['git', 'remote', 'add', 'mirror', frameworkMirror]), - const FakeCommand(command: ['git', 'fetch', 'mirror']), - const FakeCommand(command: ['git', 'checkout', 'upstream/$candidateBranch']), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', - ], - stdout: '$previousVersion-42-gabc123', - ), - //const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand( - command: ['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'], - stdout: branchPointRevision, - ), - // check if commit is tagged, zero exit code means it is tagged - const FakeCommand( - command: ['git', 'describe', '--exact-match', '--tags', branchPointRevision], - ), - - const FakeCommand( - command: ['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'], - ), - - // update DEPS - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: ['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - ]; - - final CommandRunner runner = createRunner(commands: commands); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - - await runner.run([ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - releaseChannel, - '--$kStateOption', - stateFilePath, - '--$kDartRevisionOption', - nextDartRevision, - '--$kGithubUsernameOption', - githubUsername, - ]); - - final File stateFile = fileSystem.file(stateFilePath); - - final pb.ConductorState state = pb.ConductorState(); - state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync())); - - expect(state.releaseType, ReleaseType.BETA_HOTFIX); - expect( - stdio.error, - isNot(contains('Tried to tag the branch point, however the target version')), - ); - expect(processManager, hasNoRemainingExpectations); - expect(state.isInitialized(), true); - expect(state.releaseChannel, releaseChannel); - expect(state.releaseVersion, nextVersion); - expect(state.framework.candidateBranch, candidateBranch); - expect(state.framework.startingGitHead, revision3); - expect(state.framework.upstream.url, 'git@github.com:flutter/flutter.git'); - expect(state.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS); - expect(state.conductorVersion, conductorVersion); - }); - - test('uses --$kVersionOverrideOption', () async { - stdio.stdin.add('y'); // accept prompt from ensureBranchPointTagged() - const String revision2 = 'def789'; - const String revision3 = '123abc'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-1.0.pre'; - const String candidateBranch = 'flutter-1.2-candidate.1'; - const String versionOverride = '42.0.0-42.0.pre'; - - final List commands = [ - // clone and rev-parse framework - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - FrameworkRepository.defaultUpstream, - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - ), - ], - onRun: (_) { - // ensure this is a monorepo checkout - fileSystem - .directory( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'engine', - ), - ) - .createSync(recursive: true); - fileSystem - .file( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'DEPS', - ), - ) - .writeAsStringSync(generateMockDeps(previousDartRevision)); - }, - ), - const FakeCommand(command: ['git', 'remote', 'add', 'mirror', frameworkMirror]), - const FakeCommand(command: ['git', 'fetch', 'mirror']), - const FakeCommand(command: ['git', 'checkout', 'upstream/$candidateBranch']), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', - ], - stdout: '$previousVersion-42-gabc123', - ), - const FakeCommand( - command: ['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'], - stdout: branchPointRevision, - ), - - const FakeCommand( - command: ['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: ['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - ]; - - final CommandRunner runner = createRunner(commands: commands); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - - await runner.run([ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - releaseChannel, - '--$kStateOption', - stateFilePath, - '--$kDartRevisionOption', - nextDartRevision, - '--$kVersionOverrideOption', - versionOverride, - '--$kGithubUsernameOption', - githubUsername, - ]); - - final File stateFile = fileSystem.file(stateFilePath); - - final pb.ConductorState state = pb.ConductorState(); - state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync())); - - expect(processManager, hasNoRemainingExpectations); - expect(state.releaseVersion, versionOverride); - }); - - test('can convert from dev style version to stable version', () async { - const String revision2 = 'def789'; - const String revision3 = '123abc'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-3.0.pre'; - const String nextVersion = '1.2.0'; - - final List commands = [ - // rev-parse framework - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - FrameworkRepository.defaultUpstream, - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - ), - ], - onRun: (_) { - // ensure this is a monorepo checkout - fileSystem - .directory( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'engine', - ), - ) - .createSync(recursive: true); - fileSystem - .file( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'DEPS', - ), - ) - .writeAsStringSync(generateMockDeps(previousDartRevision)); - }, - ), - const FakeCommand(command: ['git', 'remote', 'add', 'mirror', frameworkMirror]), - const FakeCommand(command: ['git', 'fetch', 'mirror']), - const FakeCommand(command: ['git', 'checkout', 'upstream/$candidateBranch']), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision3), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', - ], - stdout: '$previousVersion-42-gabc123', - ), - const FakeCommand( - command: ['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'], - stdout: branchPointRevision, - ), - // check if commit is tagged, 0 exit code thus it is tagged - const FakeCommand( - command: ['git', 'describe', '--exact-match', '--tags', branchPointRevision], - ), - - const FakeCommand( - command: ['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'], - ), - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: ['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - ]; - - final CommandRunner runner = createRunner(commands: commands); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - - await runner.run([ - 'start', - '--$kCandidateOption', - candidateBranch, - '--$kReleaseOption', - 'stable', - '--$kStateOption', - stateFilePath, - '--$kDartRevisionOption', - nextDartRevision, - '--$kGithubUsernameOption', - githubUsername, - ]); - - final File stateFile = fileSystem.file(stateFilePath); - - final pb.ConductorState state = pb.ConductorState(); - state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync())); - - expect(processManager, hasNoRemainingExpectations); - expect(state.isInitialized(), true); - expect(state.releaseChannel, 'stable'); - expect(state.releaseVersion, nextVersion); - expect(state.framework.dartRevision, nextDartRevision); - expect(state.framework.candidateBranch, candidateBranch); - expect(state.framework.startingGitHead, revision3); - expect(state.currentPhase, ReleasePhase.APPLY_FRAMEWORK_CHERRYPICKS); - expect(state.conductorVersion, conductorVersion); - expect(state.releaseType, ReleaseType.STABLE_INITIAL); - }); - - test('StartContext gets framework checkout directory after run', () async { - stdio.stdin.add('y'); - const String revision2 = 'def789'; - const String branchPointRevision = 'deadbeef'; - const String previousDartRevision = '171876a4e6cf56ee6da1f97d203926bd7afda7ef'; - const String nextDartRevision = 'f6c91128be6b77aef8351e1e3a9d07c85bc2e46e'; - const String previousVersion = '1.2.0-1.0.pre'; - // This is a git tag applied to the branch point, not an actual release - const String branchPointTag = '1.2.0-3.0.pre'; - - final Directory framework = fileSystem - .directory(checkoutsParentDirectory) - .childDirectory('flutter_conductor_checkouts') - .childDirectory('framework'); - - final List commands = [ - // checkout and rev-parse framework - FakeCommand( - command: [ - 'git', - 'clone', - '--origin', - 'upstream', - '--', - FrameworkRepository.defaultUpstream, - framework.path, - ], - onRun: (_) { - // ensure this is a monorepo checkout - fileSystem - .directory( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'engine', - ), - ) - .createSync(recursive: true); - fileSystem - .file( - fileSystem.path.join( - checkoutsParentDirectory, - 'flutter_conductor_checkouts', - 'framework', - 'DEPS', - ), - ) - .writeAsStringSync(generateMockDeps(previousDartRevision)); - }, - ), - const FakeCommand(command: ['git', 'remote', 'add', 'mirror', frameworkMirror]), - const FakeCommand(command: ['git', 'fetch', 'mirror']), - const FakeCommand(command: ['git', 'checkout', 'upstream/$candidateBranch']), - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: branchPointRevision, - ), - - const FakeCommand( - command: ['git', 'rev-parse', 'HEAD'], - stdout: branchPointRevision, - ), - const FakeCommand( - command: [ - 'git', - 'describe', - '--match', - '*.*.*', - '--tags', - 'refs/remotes/upstream/$candidateBranch', - ], - stdout: '$previousVersion-42-gabc123', - ), - const FakeCommand( - command: ['git', 'merge-base', 'upstream/$candidateBranch', 'upstream/master'], - stdout: branchPointRevision, - ), - // check if commit is tagged - const FakeCommand( - command: ['git', 'describe', '--exact-match', '--tags', branchPointRevision], - // non-zero exit code means branch point is NOT tagged - exitCode: 128, - ), - - const FakeCommand(command: ['git', 'tag', branchPointTag, branchPointRevision]), - const FakeCommand( - command: ['git', 'push', FrameworkRepository.defaultUpstream, branchPointTag], - ), - - const FakeCommand( - command: ['git', 'checkout', '-b', 'cherrypicks-$candidateBranch'], - ), - - const FakeCommand( - command: ['git', 'status', '--porcelain'], - stdout: 'MM path/to/DEPS', - ), - const FakeCommand(command: ['git', 'add', '--all']), - const FakeCommand( - command: ['git', 'commit', '--message', 'Update Dart SDK to $nextDartRevision'], - ), - const FakeCommand(command: ['git', 'rev-parse', 'HEAD'], stdout: revision2), - ]; - - final String operatingSystem = const LocalPlatform().operatingSystem; - final Map environment = {'HOME': '/path/to/user/home'}; - final Directory homeDir = fileSystem.directory(environment['HOME']); - // Tool assumes this exists - homeDir.createSync(recursive: true); - platform = FakePlatform(environment: environment, operatingSystem: operatingSystem); - - final String stateFilePath = fileSystem.path.join( - platform.environment['HOME']!, - kStateFileName, - ); - final File stateFile = fileSystem.file(stateFilePath); - - processManager = FakeProcessManager.list([...commands]); - checkouts = Checkouts( - fileSystem: fileSystem, - parentDirectory: fileSystem.directory(checkoutsParentDirectory), - platform: platform, - processManager: processManager, - stdio: stdio, - ); - - final StartContext startContext = StartContext( - candidateBranch: candidateBranch, - checkouts: checkouts, - dartRevision: nextDartRevision, - frameworkMirror: frameworkMirror, - frameworkUpstream: FrameworkRepository.defaultUpstream, - releaseChannel: releaseChannel, - processManager: processManager, - conductorVersion: conductorVersion, - githubUsername: githubUsername, - stateFile: stateFile, - ); - - await startContext.run(); - - final pb.ConductorState state = pb.ConductorState(); - state.mergeFromProto3Json(jsonDecode(stateFile.readAsStringSync())); - - expect((await startContext.framework.checkoutDirectory).path, equals(framework.path)); - expect(state.releaseType, ReleaseType.BETA_INITIAL); - expect(processManager, hasNoRemainingExpectations); - }); - }, - onPlatform: { - 'windows': const Skip('Flutter Conductor only supported on macos/linux'), - }, - ); -} - -String generateMockDeps(String dartRevision) { - return ''' -vars = { - 'chromium_git': 'https://chromium.googlesource.com', - 'swiftshader_git': 'https://swiftshader.googlesource.com', - 'dart_git': 'https://dart.googlesource.com', - 'flutter_git': 'https://flutter.googlesource.com', - 'fuchsia_git': 'https://fuchsia.googlesource.com', - 'github_git': 'https://github.com', - 'skia_git': 'https://skia.googlesource.com', - 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '4e9d5e2bdf04c58bc0bff57be7171e469e5d7175', - - 'dart_revision': '$dartRevision', - 'dart_boringssl_gen_rev': '7322fc15cc065d8d2957fccce6b62a509dc4d641', -}'''; -} diff --git a/dev/conductor/core/test/state_test.dart b/dev/conductor/core/test/state_test.dart deleted file mode 100644 index 25894a776f065..0000000000000 --- a/dev/conductor/core/test/state_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; -import 'package:conductor_core/src/state.dart'; -import 'package:file/file.dart'; -import 'package:file/memory.dart'; - -import './common.dart'; - -void main() { - test('writeStateToFile() pretty-prints JSON with 2 spaces', () { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final File stateFile = fileSystem.file('/path/to/statefile.json')..createSync(recursive: true); - const String candidateBranch = 'flutter-2.3-candidate.0'; - final pb.ConductorState state = - pb.ConductorState.create() - ..releaseChannel = 'stable' - ..releaseVersion = '2.3.4' - ..engine = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = 'git@github.com:flutter/engine.git')) - ..framework = - (pb.Repository.create() - ..candidateBranch = candidateBranch - ..upstream = - (pb.Remote.create() - ..name = 'upstream' - ..url = 'git@github.com:flutter/flutter.git')); - writeStateToFile(stateFile, state, ['[status] hello world']); - final String serializedState = stateFile.readAsStringSync(); - const String expectedString = ''' -{ - "releaseChannel": "stable", - "releaseVersion": "2.3.4", - "engine": { - "candidateBranch": "flutter-2.3-candidate.0", - "upstream": { - "name": "upstream", - "url": "git@github.com:flutter/engine.git" - } - }, - "framework": { - "candidateBranch": "flutter-2.3-candidate.0", - "upstream": { - "name": "upstream", - "url": "git@github.com:flutter/flutter.git" - } - }, - "logs": [ - "[status] hello world" - ] -}'''; - expect(serializedState, expectedString); - }); -} diff --git a/dev/conductor/core/test/version_test.dart b/dev/conductor/core/test/version_test.dart index cb367a854e44b..cc2fcb504ac58 100644 --- a/dev/conductor/core/test/version_test.dart +++ b/dev/conductor/core/test/version_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:conductor_core/src/proto/conductor_state.pbenum.dart'; import 'package:conductor_core/src/version.dart'; import 'common.dart'; @@ -103,65 +102,4 @@ void main() { 'windows': const Skip('Flutter Conductor only supported on macos/linux'), }, ); - - group('.ensureValid()', () { - test('throws when x does not match', () { - const String versionString = '1.2.3-4.5.pre'; - const String candidateBranch = 'flutter-3.2-candidate.4'; - final Version version = Version.fromString(versionString); - expect( - () => version.ensureValid(candidateBranch, ReleaseType.BETA_HOTFIX), - throwsExceptionWith( - 'Parsed version $versionString has a different x value than ' - 'candidate branch $candidateBranch', - ), - ); - }); - - test('throws when y does not match', () { - const String versionString = '1.2.3'; - const String candidateBranch = 'flutter-1.15-candidate.4'; - final Version version = Version.fromString(versionString); - expect( - () => version.ensureValid(candidateBranch, ReleaseType.BETA_INITIAL), - throwsExceptionWith( - 'Parsed version $versionString has a different y value than ' - 'candidate branch $candidateBranch', - ), - ); - }); - - test('throws when m does not match', () { - const String versionString = '1.2.3-4.5.pre'; - const String candidateBranch = 'flutter-1.2-candidate.0'; - final Version version = Version.fromString(versionString); - expect( - () => version.ensureValid(candidateBranch, ReleaseType.BETA_HOTFIX), - throwsExceptionWith( - 'Parsed version $versionString has a different m value than ' - 'candidate branch $candidateBranch', - ), - ); - }); - - test('does not validate m if version type is stable', () { - const String versionString = '1.2.0'; - const String candidateBranch = 'flutter-1.2-candidate.98'; - final Version version = Version.fromString(versionString); - expect( - () => version.ensureValid(candidateBranch, ReleaseType.STABLE_HOTFIX), - isNot(throwsException), - ); - }); - - test('throws on malformed candidate branch', () { - const String versionString = '1.2.0'; - const String candidateBranch = 'stable'; - final Version version = Version.fromString(versionString); - expect( - () => version.ensureValid(candidateBranch, ReleaseType.STABLE_HOTFIX), - throwsExceptionWith('Candidate branch $candidateBranch does not match the pattern'), - ); - }); - }); } diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 2327311d4421d..3c1f727562245 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -4,58 +4,19 @@ description: Tool to run the tests listed in the flutter/tests repository. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - args: 2.7.0 - path: 1.9.1 - glob: 2.1.3 - meta: 1.16.0 + args: any + path: any + glob: any + meta: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + file: any dev_dependencies: - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6d45 +# PUBSPEC CHECKSUM: gdtbtj diff --git a/dev/customer_testing/tests.version b/dev/customer_testing/tests.version index 0ebc04f747379..62beb57172b0b 100644 --- a/dev/customer_testing/tests.version +++ b/dev/customer_testing/tests.version @@ -1 +1 @@ -c9cbc600e3974fb5f2fe505def53f1dc11cefda7 +7f55026290e721fc648d3811664bbf3abca911d5 diff --git a/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart b/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart index ddd685646be6f..85f28b75049b9 100644 --- a/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart +++ b/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart @@ -214,6 +214,17 @@ class ModuleTest { return TaskResult.failure('Failed to build editable host .apk'); } + section('Flutter build aar succeeds'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['aar', '--no-profile'], + output: stdout, + stderr: stderr, + ); + }); + section('Add to existing Android app'); final Directory hostApp = Directory(path.join(tempDir.path, 'hello_host_app')); @@ -237,13 +248,12 @@ class ModuleTest { ); // Modify gradle version to the passed in version. - // This is somehow the wrong file. final File gradleWrapperProperties = File( path.join(hostApp.path, 'gradle', 'wrapper', 'gradle-wrapper.properties'), ); String propertyContent = await gradleWrapperProperties.readAsString(); propertyContent = propertyContent.replaceFirst('REPLACEME', gradleVersion); - section(propertyContent); + section('Modify gradle wrapper file contents'); await gradleWrapperProperties.writeAsString(propertyContent, flush: true); // Modify AGP version to the passed in version. diff --git a/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart b/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart index 81e0da65e09cf..9af9567b83384 100644 --- a/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart +++ b/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart @@ -27,15 +27,13 @@ Future main() async { ...baseApkFiles, 'lib/armeabi-v7a/libflutter.so', 'lib/arm64-v8a/libflutter.so', - // Debug mode intentionally includes `x86` and `x86_64`. - 'lib/x86/libflutter.so', + // Debug mode intentionally includes `x86_64`. 'lib/x86_64/libflutter.so', ], apkFiles); checkCollectionDoesNotContain([ 'lib/arm64-v8a/libapp.so', 'lib/armeabi-v7a/libapp.so', - 'lib/x86/libapp.so', 'lib/x86_64/libapp.so', ], apkFiles); diff --git a/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart b/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart index 643b823e46adb..5e4f4b77b7b42 100644 --- a/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart +++ b/dev/devicelab/bin/tasks/gradle_plugin_light_apk_test.dart @@ -35,31 +35,6 @@ Future main() async { checkCollectionDoesNotContain([ 'lib/arm64-v8a/libapp.so', 'lib/armeabi-v7a/libapp.so', - 'lib/x86/libapp.so', - 'lib/x86_64/libapp.so', - ], apkFiles); - - section('APK content for task assembleDebug with target platform = android-x86'); - // This is used by `flutter run` - await inDirectory(pluginProject.exampleAndroidPath, () { - return flutter( - 'build', - options: ['apk', '--debug', '--target-platform=android-x86'], - ); - }); - - apkFiles = await getFilesInApk(pluginProject.debugApkPath); - - checkCollectionContains([ - ...flutterAssets, - ...debugAssets, - ...baseApkFiles, - 'lib/x86/libflutter.so', - ], apkFiles); - - checkCollectionDoesNotContain([ - 'lib/armeabi-v7a/libapp.so', - 'lib/x86/libapp.so', 'lib/x86_64/libapp.so', ], apkFiles); @@ -84,7 +59,6 @@ Future main() async { checkCollectionDoesNotContain([ 'lib/armeabi-v7a/libapp.so', - 'lib/x86/libapp.so', 'lib/x86_64/libapp.so', ], apkFiles); diff --git a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart index c34eadb4eedda..003f85eebac0b 100644 --- a/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart +++ b/dev/devicelab/bin/tasks/ios_app_with_extensions_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; import 'package:path/path.dart' as path; +import 'package:yaml_edit/yaml_edit.dart'; Future main() async { await task(() async { @@ -16,9 +17,10 @@ Future main() async { final Directory tempDir = Directory.systemTemp.createTempSync( 'flutter_ios_app_with_extensions_test.', ); - final Directory projectDir = Directory(path.join(tempDir.path, 'app_with_extensions')); + final Directory rootDir = Directory(path.join(tempDir.path, 'app_workspace')); + final Directory projectDir = Directory(path.join(rootDir.path, 'app_with_extensions')); try { - mkdir(projectDir); + mkdirs(projectDir); recursiveCopy( Directory( path.join(flutterDirectory.path, 'dev', 'integration_tests', 'ios_app_with_extensions'), @@ -26,6 +28,14 @@ Future main() async { projectDir, ); + final String rootPubspec = + File(path.join(flutterDirectory.path, 'pubspec.yaml')).readAsStringSync(); + final YamlEditor yamlEditor = YamlEditor(rootPubspec); + yamlEditor.update(['workspace'], ['app_with_extensions']); + File(path.join(rootDir.path, 'pubspec.yaml')) + ..createSync() + ..writeAsStringSync(yamlEditor.toString()); + section('Create release build'); // This attempts to build the companion watchOS app. However, the watchOS diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 0a3c624ef03fa..f66178d1eb412 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -257,7 +257,7 @@ dependencies: }); await inDirectory(projectDir, () async { - await flutter('pub', options: ['get']); + await flutter('build', options: ['ios', '--config-only']); }); section('Add to existing iOS Objective-C app'); @@ -275,7 +275,13 @@ dependencies: section('Validate iOS Objective-C host app Podfile'); final File podfile = File(path.join(objectiveCHostApp.path, 'Podfile')); - String podfileContent = await podfile.readAsString(); + final String correctPodfileContents = await podfile.readAsString(); + final File podfileMissingPostInstall = File( + path.join(objectiveCHostApp.path, 'PodfileMissingPostInstall'), + ); + + podfile.writeAsStringSync(podfileMissingPostInstall.readAsStringSync()); + final String podFailure = await eval( 'pod', ['install'], @@ -289,18 +295,12 @@ dependencies: !podFailure.contains( 'Add `flutter_post_install(installer)` to your Podfile `post_install` block to build Flutter plugins', )) { - print(podfileContent); + print(podfile.readAsStringSync()); throw TaskResult.failure( 'pod install unexpectedly succeed without "flutter_post_install" post_install block', ); } - podfileContent = ''' -$podfileContent - -post_install do |installer| - flutter_post_install(installer) -end - '''; + String podfileContent = correctPodfileContents; await podfile.writeAsString(podfileContent, flush: true); await exec( diff --git a/dev/devicelab/bin/tasks/technical_debt__cost.dart b/dev/devicelab/bin/tasks/technical_debt__cost.dart index 2c4bc541d5eea..117623ba0a956 100644 --- a/dev/devicelab/bin/tasks/technical_debt__cost.dart +++ b/dev/devicelab/bin/tasks/technical_debt__cost.dart @@ -119,30 +119,52 @@ Future findGlobalsForTool() async { return total; } -Future countDependencies() async { - final List lines = (await evalFlutter( - 'update-packages', - options: ['--transitive-closure'], - )).split('\n'); - final int count = lines.where((String line) => line.contains('->')).length; - if (count < 2) { - throw Exception( - '"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}', - ); - } - return count; +Future countDependencies() async => _getCount({ + ...(await dependenciesAt(packageNames: const ['_flutter_packages'])), + ...(await dependenciesAt( + packageNames: const ['flutter_tools'], + workingDirectory: path.join(flutterDirectory.path, 'packages', 'flutter_tools'), + )), +}); + +Future> dependenciesAt({ + required List packageNames, + String? workingDirectory, +}) async { + final String jsonOutput = await evalFlutter( + 'pub', + options: [ + 'deps', + '--json', + if (workingDirectory != null) ...['-C', workingDirectory], + ], + ); + final Map json = jsonDecode(jsonOutput) as Map; + final List packages = json['packages'] as List; + final Iterable count = packages + .map((dynamic e) => e as Map) + .where((Map package) => packageNames.contains(package['name'])) + .expand((Map element) => element['dependencies'] as List) + .map((dynamic e) => e as String); + return count.toSet(); } -Future countConsumerDependencies() async { - final List lines = (await evalFlutter( - 'update-packages', - options: ['--transitive-closure', '--consumer-only'], - )).split('\n'); - final int count = lines.where((String line) => line.contains('->')).length; +Future countConsumerDependencies() async => _getCount( + await dependenciesAt( + packageNames: [ + 'flutter', + 'flutter_test', + 'flutter_driver', + 'flutter_localizations', + 'integration_test', + ], + ), +); + +int _getCount(Set deps) { + final int count = deps.length; if (count < 2) { - throw Exception( - '"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}', - ); + throw Exception('"flutter pub deps --json" returned bogus output.'); } return count; } diff --git a/dev/devicelab/lib/framework/devices.dart b/dev/devicelab/lib/framework/devices.dart index b7af2080eb59b..512df851d0d0a 100644 --- a/dev/devicelab/lib/framework/devices.dart +++ b/dev/devicelab/lib/framework/devices.dart @@ -1046,8 +1046,9 @@ class IosDevice extends Device { final List dylibsPaths = [ path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'libimobiledevice'), path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'openssl'), - path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'usbmuxd'), + path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'libusbmuxd'), path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'libplist'), + path.join(flutterDirectory.path, 'bin', 'cache', 'artifacts', 'libimobiledeviceglue'), ]; return dylibsPaths.join(':'); } diff --git a/dev/devicelab/lib/tasks/hot_mode_tests.dart b/dev/devicelab/lib/tasks/hot_mode_tests.dart index c4ea71084812d..2236b927d7b62 100644 --- a/dev/devicelab/lib/tasks/hot_mode_tests.dart +++ b/dev/devicelab/lib/tasks/hot_mode_tests.dart @@ -8,6 +8,7 @@ import 'dart:io'; import 'package:path/path.dart' as path; import 'package:process/process.dart'; +import 'package:yaml_edit/yaml_edit.dart'; import '../framework/devices.dart'; import '../framework/framework.dart'; @@ -15,9 +16,14 @@ import '../framework/running_processes.dart'; import '../framework/task_result.dart'; import '../framework/utils.dart'; +final Directory _editedFlutterGalleryWorkspaceDir = dir( + path.join(Directory.systemTemp.path, 'gallery_workspace'), +); + final Directory _editedFlutterGalleryDir = dir( - path.join(Directory.systemTemp.path, 'edited_flutter_gallery'), + path.join(_editedFlutterGalleryWorkspaceDir.path, 'edited_flutter_gallery'), ); + final Directory flutterGalleryDir = dir( path.join(flutterDirectory.path, 'dev/integration_tests/flutter_gallery'), ); @@ -65,6 +71,14 @@ TaskFunction createHotModeTest({ mkdirs(_editedFlutterGalleryDir); recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir); + final String rootPubspec = + File(path.join(flutterDirectory.path, 'pubspec.yaml')).readAsStringSync(); + final YamlEditor yamlEditor = YamlEditor(rootPubspec); + yamlEditor.update(['workspace'], ['edited_flutter_gallery']); + File( + path.join(_editedFlutterGalleryDir.parent.path, 'pubspec.yaml'), + ).writeAsStringSync(yamlEditor.toString()); + try { await inDirectory(_editedFlutterGalleryDir, () async { smallReloadData = await captureReloadData( diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index 4a6d28df70a5b..4b430006d639c 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -71,7 +71,10 @@ Future runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async { '--web-browser-flag=--headless=new', '--web-browser-flag=--no-sandbox', '--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true', - if (benchmarkOptions.withHotReload) '--web-experimental-hot-reload', + if (benchmarkOptions.withHotReload) + '--web-experimental-hot-reload' + else + '--no-web-experimental-hot-reload', '--no-web-resources-cdn', 'lib/web_benchmarks_ddc.dart', ], diff --git a/dev/devicelab/lib/tasks/web_dev_mode_tests.dart b/dev/devicelab/lib/tasks/web_dev_mode_tests.dart index c8d39ff943417..2e07c501ca197 100644 --- a/dev/devicelab/lib/tasks/web_dev_mode_tests.dart +++ b/dev/devicelab/lib/tasks/web_dev_mode_tests.dart @@ -7,14 +7,20 @@ import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as path; +import 'package:yaml_edit/yaml_edit.dart'; import '../framework/framework.dart'; import '../framework/task_result.dart'; import '../framework/utils.dart'; +final Directory _editedFlutterGalleryWorkspaceDir = dir( + path.join(Directory.systemTemp.path, 'gallery_workspace'), +); + final Directory _editedFlutterGalleryDir = dir( - path.join(Directory.systemTemp.path, 'edited_flutter_gallery'), + path.join(_editedFlutterGalleryWorkspaceDir.path, 'edited_flutter_gallery'), ); + final Directory flutterGalleryDir = dir( path.join(flutterDirectory.path, 'dev/integration_tests/flutter_gallery'), ); @@ -48,6 +54,15 @@ TaskFunction createWebDevModeTest(String webDevice, bool enableIncrementalCompil rmTree(_editedFlutterGalleryDir); mkdirs(_editedFlutterGalleryDir); recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir); + + final String rootPubspec = + File(path.join(flutterDirectory.path, 'pubspec.yaml')).readAsStringSync(); + final YamlEditor yamlEditor = YamlEditor(rootPubspec); + yamlEditor.update(['workspace'], ['edited_flutter_gallery']); + File( + path.join(_editedFlutterGalleryDir.parent.path, 'pubspec.yaml'), + ).writeAsStringSync(yamlEditor.toString()); + await inDirectory(_editedFlutterGalleryDir, () async { { await flutter('packages', options: ['get']); diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index a95f479b3ee3f..a6678c59a60b9 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -5,75 +5,32 @@ homepage: https://github.com/flutter/flutter environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - archive: 3.6.1 - args: 2.7.0 - file: 7.0.1 - http: 1.4.0 - logging: 1.3.0 - meta: 1.16.0 - metrics_center: 1.0.13 - path: 1.9.1 - platform: 3.1.6 - process: 5.0.3 - pubspec_parse: 1.5.0 - shelf: 1.4.2 - shelf_static: 1.1.3 - stack_trace: 1.12.1 - vm_service: 15.0.0 - web: 1.1.1 - webkit_inspection_protocol: 1.2.1 - xml: 6.5.0 - standard_message_codec: 0.0.1+4 + archive: any + args: any + file: any + logging: any + meta: any + metrics_center: any + path: any + platform: any + process: any + shelf: any + shelf_static: any + stack_trace: any + vm_service: any + webkit_inspection_protocol: any + xml: any + standard_message_codec: any - _discoveryapis_commons: 1.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.18 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - google_identity_services_web: 0.3.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis: 12.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - googleapis_auth: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + pub_semver: any + retry: any + yaml_edit: any dev_dependencies: - test: 1.26.1 - - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: any -# PUBSPEC CHECKSUM: 338c +# PUBSPEC CHECKSUM: 7sl1uq diff --git a/dev/forbidden_from_release_tests/bin/main.dart b/dev/forbidden_from_release_tests/bin/main.dart index 13cc7f7572061..931147afcbec5 100644 --- a/dev/forbidden_from_release_tests/bin/main.dart +++ b/dev/forbidden_from_release_tests/bin/main.dart @@ -116,20 +116,8 @@ class Options { argParser.addOption( 'package-config', help: 'Dart package_config.json file generated by `pub get`.', - valueHelp: path.join( - r'$FLUTTER_ROOT', - 'examples', - 'hello_world', - '.dart_tool', - 'package_config.json', - ), - defaultsTo: path.join( - fs.currentDirectory.path, - 'examples', - 'hello_world', - '.dart_tool', - 'package_config.json', - ), + valueHelp: path.join(r'$FLUTTER_ROOT', '.dart_tool', 'package_config.json'), + defaultsTo: path.join(fs.currentDirectory.path, '.dart_tool', 'package_config.json'), ); argParser.addMultiOption( 'forbidden-type', diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index 185316c35c41a..c37b3869c77a5 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -4,16 +4,14 @@ publish_to: 'none' environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - args: 2.7.0 - file: 7.0.1 - package_config: 2.2.0 - path: 1.9.1 - process: 5.0.3 - vm_snapshot_analysis: 0.7.6 + args: any + file: any + package_config: any + path: any + vm_snapshot_analysis: any - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 069b +# PUBSPEC CHECKSUM: vifrka diff --git a/dev/integration_tests/android_engine_test/pubspec.yaml b/dev/integration_tests/android_engine_test/pubspec.yaml index 4d49e4d155cf4..2a48aba4694f2 100644 --- a/dev/integration_tests/android_engine_test/pubspec.yaml +++ b/dev/integration_tests/android_engine_test/pubspec.yaml @@ -4,6 +4,8 @@ publish_to: none environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: android_driver_extensions: path: ../../tools/android_driver_extensions @@ -12,63 +14,12 @@ dependencies: flutter_driver: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: any + path: any dev_dependencies: - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + args: any -# PUBSPEC CHECKSUM: c680 +# PUBSPEC CHECKSUM: r7umvv diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 0e9c1813b1ebb..c0d61ab3805a4 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -3,6 +3,8 @@ description: Integration testing library for Android semantics environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -10,65 +12,11 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - pub_semver: 2.2.0 - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: any flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b623 +# PUBSPEC CHECKSUM: v5sljv diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 9a6182b4de3f2..91ab09533232c 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -6,94 +6,31 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - path_provider: 2.1.5 + path_provider: any # This made non-transitive to allow exact pinning # https://github.com/flutter/flutter/issues/116376 - path_provider_android: 2.2.17 - collection: 1.19.1 + collection: any assets_for_android_views: git: url: https://github.com/flutter/goldens.git ref: 64d0f6051b9b7b9933d3d16194170a38f544634a path: dev/integration_tests/assets_for_android_views - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4b9d +# PUBSPEC CHECKSUM: re4vps diff --git a/dev/integration_tests/channels/ios/Runner/AppDelegate.m b/dev/integration_tests/channels/ios/Runner/AppDelegate.m index 8fc53c3005ce7..86f5f91b9b64a 100644 --- a/dev/integration_tests/channels/ios/Runner/AppDelegate.m +++ b/dev/integration_tests/channels/ios/Runner/AppDelegate.m @@ -86,38 +86,39 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. - FlutterViewController *flutterController = - (FlutterViewController *)self.window.rootViewController; - + // This integration test still uses the old way of registering platform + // channels to test backwards compatibility after the UISceneDelegate + // migration. + id registrar = [self registrarForPlugin:@"platform-channel-test"]; ExtendedReaderWriter* extendedReaderWriter = [ExtendedReaderWriter new]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"binary-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterBinaryCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"string-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStringCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"json-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterJSONMessageCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"std-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"json-method" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterJSONMethodCodec sharedInstance]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"std-method" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMethodCodec codecWithReaderWriter:extendedReaderWriter]]]; [[FlutterBasicMessageChannel messageChannelWithName:@"std-echo" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter]] setMessageHandler:^(id message, FlutterReply reply) { diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index 0b72d18146568..dc802f05ae2fc 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -4,15 +4,12 @@ description: Integration test for platform channels. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -22,27 +19,8 @@ dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 597c +# PUBSPEC CHECKSUM: fn62d1 diff --git a/dev/integration_tests/deferred_components_test/.gitignore b/dev/integration_tests/deferred_components_test/.gitignore index 36fea878d4980..42c50b6a86d82 100644 --- a/dev/integration_tests/deferred_components_test/.gitignore +++ b/dev/integration_tests/deferred_components_test/.gitignore @@ -24,7 +24,6 @@ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 42147f1d92d54..423ee0a8b6464 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -5,75 +5,20 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -85,4 +30,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: dgjojg diff --git a/dev/integration_tests/display_cutout_rotation/.gitignore b/dev/integration_tests/display_cutout_rotation/.gitignore index 79c113f9b5017..c08861603ad68 100644 --- a/dev/integration_tests/display_cutout_rotation/.gitignore +++ b/dev/integration_tests/display_cutout_rotation/.gitignore @@ -27,7 +27,6 @@ migrate_working_dir/ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .pub-cache/ .pub/ diff --git a/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart b/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart index a42117faad32b..7c14d8ede825d 100644 --- a/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart +++ b/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart @@ -22,6 +22,9 @@ void main() { // Load app widget. await tester.pumpWidget(const MyApp()); final BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } final Iterable displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -40,6 +43,9 @@ void main() { // Load app widget. await tester.pumpWidget(const MyApp()); final BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } // Verify that app code thinks there is a left cutout. final Iterable displayFeatures = getCutouts(tester, context); @@ -60,6 +66,9 @@ void main() { // Load app widget. await tester.pumpWidget(widgetUnderTest); BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } Iterable displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -76,6 +85,9 @@ void main() { // Requery for display features after rotation. context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -116,7 +128,7 @@ Future setOrientationAndWaitUntilRotation( } while (true) { final BuildContext context = tester.element(find.byType(Text)); - if (expectedOrientation == MediaQuery.of(context).orientation) { + if (context.mounted && expectedOrientation == MediaQuery.of(context).orientation) { break; } await tester.pumpAndSettle(); diff --git a/dev/integration_tests/display_cutout_rotation/pubspec.yaml b/dev/integration_tests/display_cutout_rotation/pubspec.yaml index bab2f32b39eac..8c94118e1a6b7 100644 --- a/dev/integration_tests/display_cutout_rotation/pubspec.yaml +++ b/dev/integration_tests/display_cutout_rotation/pubspec.yaml @@ -21,6 +21,8 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, @@ -33,13 +35,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.8 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: @@ -52,7 +48,6 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: 5.0.0 integration_test: sdk: flutter @@ -61,26 +56,6 @@ dev_dependencies: # The following section is specific to Flutter packages. - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - lints: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -120,4 +95,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package -# PUBSPEC CHECKSUM: 4c82 +# PUBSPEC CHECKSUM: fn62d1 diff --git a/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj b/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj index 6b7d64dbab365..330127f6d3ec3 100644 --- a/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj +++ b/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0D569A532DDF895D00F24F69 /* TextureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D569A522DDF895D00F24F69 /* TextureViewController.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; @@ -28,6 +29,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D569A522DDF895D00F24F69 /* TextureViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TextureViewController.m; sourceTree = ""; }; + 0D569A542DDF896B00F24F69 /* TextureViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextureViewController.h; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -89,6 +92,8 @@ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 97C146F11CF9000F007C117D /* Supporting Files */, + 0D569A522DDF895D00F24F69 /* TextureViewController.m */, + 0D569A542DDF896B00F24F69 /* TextureViewController.h */, ); path = Runner; sourceTree = ""; @@ -210,6 +215,7 @@ files = ( 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 97C146F31CF9000F007C117D /* main.m in Sources */, + 0D569A532DDF895D00F24F69 /* TextureViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -281,9 +287,13 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -382,9 +392,13 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -395,9 +409,13 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h index 4734b3eb65fd9..78655f963b90c 100644 --- a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h +++ b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h @@ -5,6 +5,5 @@ #import #import -@interface AppDelegate : FlutterAppDelegate - +@interface AppDelegate : FlutterAppDelegate @end diff --git a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m index 7ad7dee967c99..0c732ec7e16ab 100644 --- a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m +++ b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m @@ -4,73 +4,5 @@ #import "AppDelegate.h" -@interface AppDelegate () - @property (atomic) uint64_t textureId; - @property (atomic) int framesProduced; - @property (atomic) int framesConsumed; - @property (atomic) int lastFrameConsumed; - @property (atomic) double startTime; - @property (atomic) double endTime; - @property (atomic) double frameRate; - @property (atomic) double frameStartTime; - @property (atomic) NSTimer* timer; - - - (void)tick:(NSTimer*)timer; -@end - @implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - FlutterViewController* flutterController = - (FlutterViewController*)self.window.rootViewController; - FlutterMethodChannel* channel = - [FlutterMethodChannel methodChannelWithName:@"texture" - binaryMessenger:flutterController]; - [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { - if ([@"start" isEqualToString:call.method]) { - _framesProduced = 0; - _framesConsumed = 0; - _frameRate = 1.0 / [(NSNumber*) call.arguments intValue]; - _timer = [NSTimer scheduledTimerWithTimeInterval:_frameRate - target:self - selector:@selector(tick:) - userInfo:nil - repeats:YES]; - _startTime = [[NSDate date] timeIntervalSince1970]; - result(nil); - } else if ([@"stop" isEqualToString:call.method]) { - [_timer invalidate]; - _endTime = [[NSDate date] timeIntervalSince1970]; - result(nil); - } else if ([@"getProducedFrameRate" isEqualToString:call.method]) { - result(@(_framesProduced / (_endTime - _startTime))); - } else if ([@"getConsumedFrameRate" isEqualToString:call.method]) { - result(@(_framesConsumed / (_endTime - _startTime))); - } else { - result(FlutterMethodNotImplemented); - } - }]; - _textureId = [flutterController registerTexture:self]; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -- (void)tick:(NSTimer*)timer { - FlutterViewController* flutterController = - (FlutterViewController*)self.window.rootViewController; - [flutterController textureFrameAvailable:_textureId]; - _frameStartTime = [[NSDate date] timeIntervalSince1970]; - // We just pretend to be producing a frame. - _framesProduced++; -} - -- (CVPixelBufferRef)copyPixelBuffer { - double now = [[NSDate date] timeIntervalSince1970]; - if (now < _frameStartTime - || _frameStartTime + _frameRate < now - || _framesProduced == _lastFrameConsumed) return nil; - _framesConsumed++; - _lastFrameConsumed = _framesProduced; - // We just pretend to be handing over the produced frame to the consumer. - return nil; -} @end diff --git a/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard b/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard index f3c28516fb38e..5f7cd2ca2e66d 100644 --- a/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard +++ b/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard @@ -1,26 +1,29 @@ - - + + + - + + - + - + - + - + + diff --git a/dev/conductor/core/lib/proto.dart b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.h similarity index 64% rename from dev/conductor/core/lib/proto.dart rename to dev/integration_tests/external_textures/ios/Runner/TextureViewController.h index bb8939908d3cb..cb8eceffa033a 100644 --- a/dev/conductor/core/lib/proto.dart +++ b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.h @@ -2,5 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -export 'src/proto/conductor_state.pb.dart'; -export 'src/proto/conductor_state.pbenum.dart'; +#import + +@interface TextureViewController : FlutterViewController +@end diff --git a/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m new file mode 100644 index 0000000000000..32f0ef3e05ffb --- /dev/null +++ b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "TextureViewController.h" +#import "AppDelegate.h" + +@interface TextureViewController () +@property (nonatomic, assign) uint64_t textureId; +@property (nonatomic, assign) int framesProduced; +@property (nonatomic, assign) int framesConsumed; +@property (nonatomic, assign) int lastFrameConsumed; +@property (nonatomic, assign) double startTime; +@property (nonatomic, assign) double endTime; +@property (nonatomic, assign) double frameRate; +@property (nonatomic, assign) double frameStartTime; +@property (nonatomic, strong) NSTimer* timer; +- (void)tick:(NSTimer*)timer; +@end + +@implementation TextureViewController + +- (void)awakeFromNib { + [super awakeFromNib]; + + FlutterMethodChannel* channel = + [FlutterMethodChannel methodChannelWithName:@"texture" + binaryMessenger:self.binaryMessenger]; + [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { + if ([@"start" isEqualToString:call.method]) { + _framesProduced = 0; + _framesConsumed = 0; + _frameRate = 1.0 / [(NSNumber*) call.arguments intValue]; + _timer = [NSTimer scheduledTimerWithTimeInterval:_frameRate + target:self + selector:@selector(tick:) + userInfo:nil + repeats:YES]; + _startTime = [[NSDate date] timeIntervalSince1970]; + result(nil); + } else if ([@"stop" isEqualToString:call.method]) { + [_timer invalidate]; + _endTime = [[NSDate date] timeIntervalSince1970]; + result(nil); + } else if ([@"getProducedFrameRate" isEqualToString:call.method]) { + result(@(_framesProduced / (_endTime - _startTime))); + } else if ([@"getConsumedFrameRate" isEqualToString:call.method]) { + result(@(_framesConsumed / (_endTime - _startTime))); + } else { + result(FlutterMethodNotImplemented); + } + }]; + + _textureId = [self registerTexture:self]; +} + +- (void)tick:(NSTimer*)timer { + [self textureFrameAvailable:_textureId]; + _frameStartTime = [[NSDate date] timeIntervalSince1970]; + // We just pretend to be producing a frame. + _framesProduced++; +} + +- (CVPixelBufferRef)copyPixelBuffer { + double now = [[NSDate date] timeIntervalSince1970]; + if (now < _frameStartTime + || _frameStartTime + _frameRate < now + || _framesProduced == _lastFrameConsumed) return nil; + _framesConsumed++; + _lastFrameConsumed = _framesProduced; + // We just pretend to be handing over the produced frame to the consumer. + return nil; +} + +@end diff --git a/dev/integration_tests/external_textures/pubspec.yaml b/dev/integration_tests/external_textures/pubspec.yaml index 5b72726edd1c3..067f17e4f9b89 100644 --- a/dev/integration_tests/external_textures/pubspec.yaml +++ b/dev/integration_tests/external_textures/pubspec.yaml @@ -4,67 +4,17 @@ description: A test of Flutter integrating external textures. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: muq7bk diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 27d356b076c01..1ad3f9644d373 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -4,6 +4,8 @@ description: Integration test for build flavors. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -11,70 +13,13 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -87,4 +32,4 @@ flutter: flavors: - free -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: rnq93o diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/selection_controls_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/selection_controls_demo.dart index 00d8a13e261ab..7e44fd44981bf 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/selection_controls_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/selection_controls_demo.dart @@ -155,9 +155,9 @@ class _SelectionControlsDemoState extends State { const Row( mainAxisSize: MainAxisSize.min, children: [ - Radio(value: 0, groupValue: 0, onChanged: null), - Radio(value: 1, groupValue: 0, onChanged: null), - Radio(value: 2, groupValue: 0, onChanged: null), + Radio(value: 0, groupValue: 0), + Radio(value: 1, groupValue: 0), + Radio(value: 2, groupValue: 0), ], ), ], diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/example_code.dart b/dev/integration_tests/flutter_gallery/lib/gallery/example_code.dart index 573fbdabc7833..36c7e6d64ab6b 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/example_code.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/example_code.dart @@ -179,7 +179,7 @@ class SelectionControls { ); // Creates a disabled radio button. - const Radio(value: 0, groupValue: 0, onChanged: null); + const Radio(value: 0, groupValue: 0); // END // START selectioncontrols_switch diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index e51b8f1f97014..67a855dff1baa 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -3,45 +3,25 @@ name: flutter_gallery environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - collection: 1.19.1 - intl: 0.20.2 - string_scanner: 1.4.1 - url_launcher: 6.3.1 - cupertino_icons: 1.0.8 - video_player: 2.9.5 - scoped_model: 2.0.0 - shrine_images: 2.0.2 + collection: any + intl: any + string_scanner: any + url_launcher: any + cupertino_icons: any + video_player: any + scoped_model: any # Also update dev/benchmarks/complex_layout/pubspec.yaml # and dev/benchmarks/macrobenchmarks/pubspec.yaml - flutter_gallery_assets: 1.0.2 + flutter_gallery_assets: any - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - csslib: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - html: 0.15.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_android: 6.3.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_ios: 6.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_linux: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_macos: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_windows: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_android: 2.8.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_avfoundation: 2.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_platform_interface: 6.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - video_player_web: 2.3.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any + vector_math: any dev_dependencies: flutter_test: @@ -50,58 +30,11 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.26.1 + test: any integration_test: sdk: flutter - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # 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.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: any flutter: uses-material-design: true @@ -273,4 +206,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: e06e +# PUBSPEC CHECKSUM: cs2d7l diff --git a/dev/integration_tests/flutter_gallery/test/demo/material/expansion_panels_demo_test.dart b/dev/integration_tests/flutter_gallery/test/demo/material/expansion_panels_demo_test.dart index 8bdbf07e2c794..4d91356fe6cbe 100644 --- a/dev/integration_tests/flutter_gallery/test/demo/material/expansion_panels_demo_test.dart +++ b/dev/integration_tests/flutter_gallery/test/demo/material/expansion_panels_demo_test.dart @@ -38,14 +38,15 @@ Widget get _radioPanelExpandIcon => _expandIcons.evaluate().toList()[1].widget; bool _isRadioSelected(int index) => _radios[index].value == _radios[index].groupValue; -List> get _radios => - List>.from(_radioFinder.evaluate().map((Element e) => e.widget)); +List> get _radios => List>.from( + _radioFinder.evaluate().map((Element e) => e.widget), +); // [find.byType] and [find.widgetWithText] do not match subclasses; `Radio` is // not sufficient to find a `Radio<_Location>`. Another approach is to grab the // `runtimeType` of a dummy instance; see // packages/flutter/test/material/radio_list_tile_test.dart. -Finder get _radioFinder => find.byWidgetPredicate((Widget w) => w is Radio); +Finder get _radioFinder => find.byWidgetPredicate((Widget w) => w is RadioListTile); List> get _radioListTiles => List>.from( _radioListTilesFinder.evaluate().map((Element e) => e.widget), diff --git a/dev/integration_tests/hook_user_defines/.gitignore b/dev/integration_tests/hook_user_defines/.gitignore index da66cc90cd842..61cc7d56fbf2a 100644 --- a/dev/integration_tests/hook_user_defines/.gitignore +++ b/dev/integration_tests/hook_user_defines/.gitignore @@ -26,7 +26,6 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages build/ diff --git a/dev/integration_tests/hook_user_defines/pubspec.yaml b/dev/integration_tests/hook_user_defines/pubspec.yaml index 0a4c566d38691..c1ae88451268e 100644 --- a/dev/integration_tests/hook_user_defines/pubspec.yaml +++ b/dev/integration_tests/hook_user_defines/pubspec.yaml @@ -5,74 +5,19 @@ version: 0.0.1 environment: sdk: ^3.7.0-0 +resolution: workspace + hooks: user_defines: hook_user_defines: # package name magic_value: 1000 dependencies: - code_assets: 0.19.0 - hooks: 0.19.1 - logging: 1.3.0 - native_toolchain_c: 0.16.1 - - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + hooks: any + logging: any + native_toolchain_c: any dev_dependencies: - ffi: 2.1.4 - ffigen: 19.0.0 - flutter_lints: 5.0.0 - test: 1.26.1 - - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_util: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_style: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - lints: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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" - quiver: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml_edit: 2.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: any -# PUBSPEC CHECKSUM: b4e9 +# PUBSPEC CHECKSUM: meinbq diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/.gitignore b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/.gitignore index cdecf14aaa300..38cd964c87cd7 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/.gitignore +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/.gitignore @@ -38,4 +38,3 @@ Icon? build/ .android/ .ios/ -.flutter-plugins 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 4a43975bda9a4..ccfca058736aa 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -16,19 +16,16 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.8 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any dev_dependencies: integration_test: @@ -39,22 +36,6 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: # The following line ensures that the Material Icons font is @@ -104,4 +85,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: fvge9g diff --git a/dev/integration_tests/ios_app_with_extensions/.gitignore b/dev/integration_tests/ios_app_with_extensions/.gitignore index 78b3c2b336438..d398c95671e38 100644 --- a/dev/integration_tests/ios_app_with_extensions/.gitignore +++ b/dev/integration_tests/ios_app_with_extensions/.gitignore @@ -23,7 +23,6 @@ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index a152704959671..1e11a1732eb9c 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -15,6 +15,8 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -22,13 +24,6 @@ dependencies: # to prompt the tool to run pod install. device_info: 2.0.3 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -39,22 +34,6 @@ dev_dependencies: # The following section is specific to Flutter. - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -94,4 +73,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 8478 +# PUBSPEC CHECKSUM: 60tnc diff --git a/dev/integration_tests/ios_host_app/Podfile b/dev/integration_tests/ios_host_app/Podfile index 1301ea35cc8d1..4662a55328449 100644 --- a/dev/integration_tests/ios_host_app/Podfile +++ b/dev/integration_tests/ios_host_app/Podfile @@ -10,3 +10,7 @@ end target 'FlutterUITests' do inherit! :search_paths end + +post_install do |installer| + flutter_post_install(installer) +end diff --git a/dev/integration_tests/ios_host_app/PodfileMissingPostInstall b/dev/integration_tests/ios_host_app/PodfileMissingPostInstall new file mode 100644 index 0000000000000..1301ea35cc8d1 --- /dev/null +++ b/dev/integration_tests/ios_host_app/PodfileMissingPostInstall @@ -0,0 +1,12 @@ +platform :ios, '13.0' + +flutter_application_path = '../hello' +load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') + +target 'Host' do + install_all_flutter_pods flutter_application_path +end + +target 'FlutterUITests' do + inherit! :search_paths +end diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index a411871ef8511..827c3e9cc61e6 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -5,75 +5,20 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -82,4 +27,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: dgjojg diff --git a/dev/integration_tests/keyboard_hot_restart/pubspec.yaml b/dev/integration_tests/keyboard_hot_restart/pubspec.yaml index 32c0d660cbf3c..50ecb2c523bb6 100644 --- a/dev/integration_tests/keyboard_hot_restart/pubspec.yaml +++ b/dev/integration_tests/keyboard_hot_restart/pubspec.yaml @@ -7,17 +7,14 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: h86dcv diff --git a/dev/integration_tests/link_hook/pubspec.yaml b/dev/integration_tests/link_hook/pubspec.yaml index 237957a8a5341..e883a43878e64 100644 --- a/dev/integration_tests/link_hook/pubspec.yaml +++ b/dev/integration_tests/link_hook/pubspec.yaml @@ -5,69 +5,15 @@ version: 0.0.1 environment: sdk: ^3.7.0-0 -dependencies: - code_assets: 0.19.0 - hooks: 0.19.1 - logging: 1.3.0 - native_toolchain_c: 0.16.1 +resolution: workspace - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" +dependencies: + code_assets: any + hooks: any + logging: any + native_toolchain_c: any dev_dependencies: - ffi: 2.1.4 - ffigen: 19.0.0 - flutter_lints: 5.0.0 - test: 1.26.1 - - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_util: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_style: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - lints: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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" - quiver: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml_edit: 2.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: any -# PUBSPEC CHECKSUM: b4e9 +# PUBSPEC CHECKSUM: seumf2 diff --git a/dev/integration_tests/new_gallery/lib/demos/material/selection_controls_demo.dart b/dev/integration_tests/new_gallery/lib/demos/material/selection_controls_demo.dart index b8c01afb68b35..f3b5804228702 100644 --- a/dev/integration_tests/new_gallery/lib/demos/material/selection_controls_demo.dart +++ b/dev/integration_tests/new_gallery/lib/demos/material/selection_controls_demo.dart @@ -167,7 +167,7 @@ class _RadioDemoState extends State<_RadioDemo> with RestorationMixin { mainAxisAlignment: MainAxisAlignment.center, children: [ for (int index = 0; index < 2; ++index) - Radio(value: index, groupValue: radioValue.value, onChanged: null), + Radio(value: index, groupValue: radioValue.value), ], ), ], diff --git a/dev/integration_tests/new_gallery/pubspec.yaml b/dev/integration_tests/new_gallery/pubspec.yaml index 03779e6946ac2..4c6d210e1a31d 100644 --- a/dev/integration_tests/new_gallery/pubspec.yaml +++ b/dev/integration_tests/new_gallery/pubspec.yaml @@ -6,110 +6,35 @@ version: 2.10.2+021002 # See README.md for details on versioning. environment: flutter: ^3.13.0 sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter - adaptive_breakpoints: 0.1.7 - animations: 2.0.11 - collection: 1.19.1 - cupertino_icons: 1.0.8 - flutter_gallery_assets: 1.0.2 - flutter_localized_locales: 2.0.5 - flutter_staggered_grid_view: 0.7.0 - google_fonts: 6.2.1 - intl: 0.20.2 - meta: 1.16.0 - provider: 6.1.5 - rally_assets: 3.0.1 - scoped_model: 2.0.0 - shrine_images: 2.0.2 - url_launcher: 6.3.1 - vector_math: 2.1.4 + adaptive_breakpoints: any + animations: any + collection: any + flutter_localized_locales: any + flutter_staggered_grid_view: any + google_fonts: any + intl: any + provider: any + scoped_model: any + url_launcher: any + vector_math: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - nested: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.2.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_android: 6.3.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_ios: 6.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_linux: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_macos: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_windows: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + nested: any dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # 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.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -312,4 +237,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: d3dd +# PUBSPEC CHECKSUM: ltolmu diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index b7eb6379f103d..8aaf652d49dbc 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -4,67 +4,17 @@ description: Integration test for platform interactions. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: muq7bk diff --git a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle index 518a685691b97..f21e519eb06bd 100644 --- a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle +++ b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle @@ -29,8 +29,15 @@ android { versionCode 1 versionName "1.0" } + buildTypes { + profile { + initWith debug + } + } } dependencies { - implementation project(':flutter') + debugImplementation 'io.flutter.devicelab.hello:flutter_debug:1.0' + profileImplementation 'io.flutter.devicelab.hello:flutter_profile:1.0' + releaseImplementation 'io.flutter.devicelab.hello:flutter_release:1.0' } diff --git a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle index 6c933debbaf4c..5368feb7ecde7 100644 --- a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle +++ b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle @@ -2,6 +2,44 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + google() + mavenCentral() + def flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://storage.googleapis.com" + maven { + url = uri("$flutterStorageUrl/download.flutter.io") + } + maven { + url = uri("../hello/build/host/outputs/repo") + } + // BEGIN ci only configuration for getting engine artifacts in pre-submit environments + def flutterSdkPath = { + def properties = new Properties() + file("../hello/.android/local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + + settings.ext.flutterSdkPath = flutterSdkPath() + + def engineRealm = + new File("${settings.ext.flutterSdkPath}/bin/cache/engine.realm") + .getText('UTF-8') + .trim() + + if (engineRealm) { // In Groovy, a non-empty string is true + engineRealm += "/" + } + + maven { + url = uri("${flutterStorageUrl}/${engineRealm}download.flutter.io") + } + + // END ci only configuration for getting engine artifacts in pre-submit environments + } +} + include ':app' -setBinding(new Binding([gradle: this])) -evaluate(new File(settingsDir.parentFile, 'hello/.android/include_flutter.groovy')) diff --git a/dev/integration_tests/release_smoke_test/.gitignore b/dev/integration_tests/release_smoke_test/.gitignore index fa4e4b701e02b..5593148766232 100644 --- a/dev/integration_tests/release_smoke_test/.gitignore +++ b/dev/integration_tests/release_smoke_test/.gitignore @@ -23,7 +23,6 @@ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 7288e92330ff5..37a44c6e78d5b 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -3,15 +3,12 @@ name: release_smoke_test environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -19,21 +16,5 @@ dev_dependencies: integration_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: vrimb3 diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index e5033a20465b4..4704fe6c3d8e0 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -20,6 +20,8 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, @@ -34,11 +36,6 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: 1.0.8 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -53,22 +50,6 @@ dev_dependencies: # The following section is specific to Flutter packages. - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -108,4 +89,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: ovmend diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index c37497161b980..faef519637be8 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -4,6 +4,8 @@ description: Flutter non-plugin UI integration tests. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -11,74 +13,18 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any dev_dependencies: flutter_test: sdk: flutter - test_api: 0.7.6 - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/foo.png -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 77jv2r diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index 713cd30ee0cee..cc580d2d47ea6 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -4,6 +4,8 @@ description: Integration test for web compilation. environment: sdk: ^3.7.0-0 +resolution: workspace + flutter: assets: - lib/a.dart @@ -14,12 +16,9 @@ dependencies: flutter: sdk: flutter - web: 1.1.1 + web: any - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + meta: any -# PUBSPEC CHECKSUM: e351 +# PUBSPEC CHECKSUM: 920vbf diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index b5be54d6e95cc..2639928c762a0 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -2,14 +2,11 @@ name: web_compile_tests environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: h86dcv diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 4202db0a828be..7d689d1b1e39a 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -4,6 +4,8 @@ publish_to: none environment: sdk: ^3.7.0-0 +resolution: workspace + flutter: assets: - packages/flutter_gallery_assets/assets/icons/material/1.5x/material.png @@ -20,73 +22,12 @@ dependencies: sdk: flutter integration_test: sdk: flutter - flutter_gallery_assets: 1.0.2 - web: 1.1.1 + web: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: sdk: flutter - http: 1.4.0 - test: 1.26.1 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ef1b +# PUBSPEC CHECKSUM: d6lgr diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index c7a9bda964265..9b0462d8f6fe0 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -7,15 +7,12 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -23,24 +20,8 @@ dev_dependencies: integration_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: vrimb3 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index e6dcd10ecab91..1f296623f9bf6 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -4,64 +4,14 @@ description: Integration test for Windows app's startup. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: muq7bk diff --git a/dev/manual_tests/.gitignore b/dev/manual_tests/.gitignore index 0fa6b675c0a52..d7a08d45a4b49 100644 --- a/dev/manual_tests/.gitignore +++ b/dev/manual_tests/.gitignore @@ -24,7 +24,6 @@ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 44baa2aa30628..3a2eec1dacdaa 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -3,38 +3,19 @@ name: manual_tests environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/dev/snippets/pubspec.yaml b/dev/snippets/pubspec.yaml index a990193ea6a76..2bb293f402008 100644 --- a/dev/snippets/pubspec.yaml +++ b/dev/snippets/pubspec.yaml @@ -4,63 +4,24 @@ description: A package for parsing and manipulating code samples in Flutter repo environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - analyzer: 7.4.5 - args: 2.7.0 - file: 7.0.1 - meta: 1.16.0 - path: 1.9.1 - platform: 3.1.6 - process: 5.0.3 + analyzer: any + args: any + file: any + meta: any + path: any + platform: any + process: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pub_semver: any dev_dependencies: - test: 1.26.1 + test: any - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" executables: snippets: -# PUBSPEC CHECKSUM: e050 +# PUBSPEC CHECKSUM: o4c1ki diff --git a/dev/tools/android_driver_extensions/pubspec.yaml b/dev/tools/android_driver_extensions/pubspec.yaml index 0bec3a6381a4a..3be9660559549 100644 --- a/dev/tools/android_driver_extensions/pubspec.yaml +++ b/dev/tools/android_driver_extensions/pubspec.yaml @@ -3,6 +3,8 @@ name: android_driver_extensions environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -12,69 +14,17 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - matcher: 0.12.17 - meta: 1.16.0 - path: 1.9.1 - platform: 3.1.6 - process: 5.0.3 - test_api: 0.7.6 + matcher: any + meta: any + path: any + platform: any + process: any + test_api: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: any dev_dependencies: - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c572 +# PUBSPEC CHECKSUM: 82inqh diff --git a/dev/tools/bin/check_engine_version.dart b/dev/tools/bin/check_engine_version.dart new file mode 100644 index 0000000000000..5a6bcda9d89a7 --- /dev/null +++ b/dev/tools/bin/check_engine_version.dart @@ -0,0 +1,48 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io' as io; + +import 'package:args/args.dart'; +import 'package:dev_tools/check_engine_version.dart'; +import 'package:path/path.dart' as p; + +final String _scriptSuffix = io.Platform.isWindows ? '.bat' : '.sh'; +final ArgParser _argParser = + ArgParser() + ..addOption( + 'version', + abbr: 'v', + help: 'Path to the engine.version file', + defaultsTo: p.join('bin', 'internal', 'engine.version'), + ) + ..addOption( + 'script', + abbr: 'l', + help: 'Path to the last_engine_commit$_scriptSuffix script', + defaultsTo: p.join('bin', 'internal', 'last_engine_commit$_scriptSuffix'), + ) + ..addFlag( + 'skip-if-version-file-not-changed-from-head', + help: 'Skips the check, if the file was not changed compared to HEAD', + defaultsTo: true, + ); + +/// Checks if `bin/internal/engine.version` was updated to the current SHA. +void main(List args) async { + final ArgResults argResults = _argParser.parse(args); + + final String versionPath = argResults.option('version')!; + final String scriptPath = argResults.option('script')!; + final bool skipIfNotChanged = argResults.flag('skip-if-version-file-not-changed-from-head'); + + final bool result = await checkEngineVersion( + versionPath: versionPath, + scriptPath: scriptPath, + onlyIfVersionChanged: skipIfNotChanged, + ); + if (!result) { + io.exitCode = 1; + } +} diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index ec88667ec2f8a..83476473d9805 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -5,57 +5,14 @@ version: 1.0.0 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - args: 2.7.0 + args: any dev_dependencies: - path: 1.9.1 - test: 1.26.1 + path: any + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6d45 +# PUBSPEC CHECKSUM: vbgshi diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 50af4604b8a72..1985e75a8bda2 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -4,60 +4,17 @@ description: Generates keycode source files from various resources. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - args: 2.7.0 - http: 1.4.0 - meta: 1.16.0 - path: 1.9.1 - platform: 3.1.6 + args: any + http: any + meta: any + path: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.26.1 - test_api: 0.7.6 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 440d +# PUBSPEC CHECKSUM: mronmk diff --git a/dev/tools/lib/check_engine_version.dart b/dev/tools/lib/check_engine_version.dart new file mode 100644 index 0000000000000..39f43f2f61688 --- /dev/null +++ b/dev/tools/lib/check_engine_version.dart @@ -0,0 +1,91 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io' as io; + +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:meta/meta.dart'; +import 'package:process_runner/process_runner.dart'; + +/// Checks if the contents of [versionPath] are the same as the output of [scriptPath]. +/// +/// ```dart +/// final bool success = await checkEngineVersion( +/// versionPath: 'bin/internal/engine.version', +/// scriptPath: 'bin/internal/last_engine_commit.sh', +/// ); +/// ``` +/// +/// If the file described at [versionPath] does not exist, this check returns `true`. +/// +/// If [onlyIfVersionChanged] is `true` (default), and the file described by [versionPath] +/// has not changed at the current commit SHA compared to HEAD, `true` is immediately +/// returned without any additional checks. +@useResult +Future checkEngineVersion({ + required String versionPath, + required String scriptPath, + bool onlyIfVersionChanged = true, + @visibleForTesting FileSystem? fileSystem, + @visibleForTesting ProcessRunner? runner, + @visibleForTesting StringSink? stderr, +}) async { + fileSystem ??= const LocalFileSystem(); + runner ??= ProcessRunner(); + stderr ??= io.stderr; + + // If the file does not exist, immediately return true. + final File versionFile = fileSystem.file(versionPath); + if (!versionFile.existsSync()) { + stderr.writeln('$versionPath does not exist, skipping engine.version check'); + return true; + } + + // The file exists. Do we need to verify it was updated? + if (onlyIfVersionChanged && !await _wasUpdated(versionPath, runner, stderr)) { + stderr.writeln('$versionPath has not changed, skipping engine.version check'); + return true; + } + + // Get the expected value. + final ProcessRunnerResult expectedShaResult = await runner.runProcess([ + scriptPath, + ], failOk: true); + if (expectedShaResult.exitCode != 0) { + stderr.writeln('$scriptPath failed: ${expectedShaResult.stdout}'); + return false; + } + final String expectedSha = expectedShaResult.stdout.trim(); + + // Get the actual value. + final String actualSha = versionFile.readAsStringSync().trim(); + + // Compare + if (expectedSha != actualSha) { + stderr.writeln('$scriptPath output $expectedSha, but $versionPath is $actualSha'); + return false; + } + + return true; +} + +Future _wasUpdated(String path, ProcessRunner runner, StringSink stderr) async { + final ProcessRunnerResult diffResult = await runner.runProcess([ + 'git', + 'diff', + '--name-only', + '--relative', + 'master...HEAD', + '--', + path, + ], failOk: true); + if (diffResult.exitCode != 0) { + stderr.writeln('git diff failed: ${diffResult.stdout}'); + return false; + } + + final String diffOutput = diffResult.stdout.trim(); + return diffOutput.split('\n').contains(path); +} diff --git a/dev/tools/localization/bin/gen_date_localizations.dart b/dev/tools/localization/bin/gen_date_localizations.dart index 169ee7bcb7b74..8b1895bbe366a 100644 --- a/dev/tools/localization/bin/gen_date_localizations.dart +++ b/dev/tools/localization/bin/gen_date_localizations.dart @@ -46,9 +46,7 @@ Future main(List rawArgs) async { final bool writeToFile = parseArgs(rawArgs).writeToFile; - final File packageConfigFile = File( - path.join('packages', 'flutter_localizations', '.dart_tool', 'package_config.json'), - ); + final File packageConfigFile = File(path.join('.dart_tool', 'package_config.json')); final bool packageConfigExists = packageConfigFile.existsSync(); if (!packageConfigExists) { diff --git a/dev/tools/localization/bin/gen_missing_localizations.dart b/dev/tools/localization/bin/gen_missing_localizations.dart index 8a23fe2dd1089..50a82be813070 100644 --- a/dev/tools/localization/bin/gen_missing_localizations.dart +++ b/dev/tools/localization/bin/gen_missing_localizations.dart @@ -42,6 +42,7 @@ Future main(List rawArgs) async { ); updateMissingResources(localizationPath, 'material', removeUndefined: removeUndefined); updateMissingResources(localizationPath, 'cupertino', removeUndefined: removeUndefined); + updateMissingResources(localizationPath, 'widgets', removeUndefined: removeUndefined); } Map loadBundle(File file) { diff --git a/dev/tools/mega_gallery.dart b/dev/tools/mega_gallery.dart index 93ab0d09efacf..e1961eb7f6de6 100644 --- a/dev/tools/mega_gallery.dart +++ b/dev/tools/mega_gallery.dart @@ -6,6 +6,7 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:path/path.dart' as path; +import 'package:yaml_edit/yaml_edit.dart'; /// If no `copies` param is passed in, we scale the generated app up to 60k lines. const int kTargetLineCount = 60 * 1024; @@ -18,7 +19,7 @@ void main(List args) { } final ArgParser argParser = ArgParser(); - argParser.addOption('out'); + argParser.addOption('out', mandatory: true); argParser.addOption('copies'); argParser.addFlag('delete', negatable: false); argParser.addFlag('help', abbr: 'h', negatable: false); @@ -33,12 +34,13 @@ void main(List args) { } final Directory source = Directory(_normalize('dev/integration_tests/flutter_gallery')); - final Directory out = Directory(_normalize(results['out'] as String)); + final Directory outParent = Directory(_normalize(results['out'] as String)); + final Directory out = Directory(path.join(outParent.path, 'packages')); if (results['delete'] as bool) { - if (out.existsSync()) { - print('Deleting ${out.path}'); - out.deleteSync(recursive: true); + if (outParent.existsSync()) { + print('Deleting ${outParent.path}'); + outParent.deleteSync(recursive: true); } exit(0); @@ -83,9 +85,11 @@ void main(List args) { _createEntry(_file(out, 'lib/main.dart'), copies); // Update the pubspec. - String pubspec = _file(out, 'pubspec.yaml').readAsStringSync(); - pubspec = pubspec.replaceAll('../../packages/flutter', '../../../packages/flutter'); - _file(out, 'pubspec.yaml').writeAsStringSync(pubspec); + final String pubspec = _file(Directory(''), 'pubspec.yaml').readAsStringSync(); + + final YamlEditor yamlEditor = YamlEditor(pubspec); + yamlEditor.update(['workspace'], ['packages']); + File(path.join(outParent.path, 'pubspec.yaml')).writeAsStringSync(yamlEditor.toString()); // Replace the (flutter_gallery specific) analysis_options.yaml file with a default one. _file(out, 'analysis_options.yaml').writeAsStringSync(''' diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index d8f6bf2325e98..6f210527206d3 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -4,67 +4,30 @@ description: Various repository development tools for flutter. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - archive: 3.6.1 - args: 2.7.0 - http: 1.4.0 - intl: 0.20.2 - meta: 1.16.0 - path: 1.9.1 - process: 5.0.3 - process_runner: 4.2.0 - pub_semver: 2.2.0 - yaml: 3.1.3 + archive: any + args: any + http: any + intl: any + meta: any + path: any + process: any + process_runner: any + pub_semver: any + yaml: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + file: any + platform: any + yaml_edit: any dev_dependencies: - test: 1.26.1 - test_api: 0.7.6 + test: any + test_api: any - file_testing: 3.0.2 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: any -# PUBSPEC CHECKSUM: 04bb +# PUBSPEC CHECKSUM: k73ud7 diff --git a/dev/tools/test/check_engine_version_test.dart b/dev/tools/test/check_engine_version_test.dart new file mode 100644 index 0000000000000..14c6d9e962209 --- /dev/null +++ b/dev/tools/test/check_engine_version_test.dart @@ -0,0 +1,150 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@TestOn('vm') +library; + +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:dev_tools/check_engine_version.dart' as lib; +import 'package:file/memory.dart'; +import 'package:process_runner/process_runner.dart'; +import 'package:test/fake.dart'; +import 'package:test/test.dart'; + +void main() { + late MemoryFileSystem fileSystem; + late StringBuffer stderr; + late String versionPath; + late String scriptPath; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + versionPath = fileSystem.path.join('bin', 'internal', 'engine.version'); + scriptPath = fileSystem.path.join('bin', 'internal', 'last_engine_commit.sh'); + + stderr = StringBuffer(); + }); + + tearDown(() { + printOnFailure('$stderr'); + }); + + test('skips check, returning true, if the file is missing', () async { + final ProcessRunner noRuns = FakeProcessRunner({}); + await expectLater( + lib.checkEngineVersion( + versionPath: versionPath, + scriptPath: scriptPath, + fileSystem: fileSystem, + runner: noRuns, + stderr: stderr, + ), + completion(isTrue), + ); + + expect('$stderr', contains('does not exist, skipping engine.version check')); + }); + + test('skips check, returning true, if file was not changed', () async { + fileSystem + .directory('bin') + .childDirectory('internal') + .childFile('engine.version') + .createSync(recursive: true); + + final ProcessRunner gitExec = FakeProcessRunner({ + 'git diff --name-only --relative master...HEAD -- $versionPath': ProcessRunnerResult( + 0, + utf8.encode('dev/another/file.txt\n'), + [], + [], + ), + }); + + await expectLater( + lib.checkEngineVersion( + versionPath: versionPath, + scriptPath: scriptPath, + fileSystem: fileSystem, + runner: gitExec, + stderr: stderr, + ), + completion(isTrue), + ); + + expect('$stderr', contains('has not changed, skipping engine.version check')); + }); + + test('fails if the SHAs are different', () async { + fileSystem.directory('bin').childDirectory('internal').childFile('engine.version') + ..createSync(recursive: true) + ..writeAsStringSync('def456'); + + final ProcessRunner scriptExec = FakeProcessRunner({ + scriptPath: ProcessRunnerResult(0, utf8.encode('abc123'), [], []), + }); + + await expectLater( + lib.checkEngineVersion( + versionPath: versionPath, + scriptPath: scriptPath, + fileSystem: fileSystem, + runner: scriptExec, + stderr: stderr, + onlyIfVersionChanged: false, + ), + completion(isFalse), + ); + + expect('$stderr', stringContainsInOrder(['output abc123', 'is def456'])); + }); + + test('succeeds if the SHAs are the same', () async { + fileSystem.directory('bin').childDirectory('internal').childFile('engine.version') + ..createSync(recursive: true) + ..writeAsStringSync('abc123'); + + final ProcessRunner scriptExec = FakeProcessRunner({ + scriptPath: ProcessRunnerResult(0, utf8.encode('abc123'), [], []), + }); + + await expectLater( + lib.checkEngineVersion( + versionPath: versionPath, + scriptPath: scriptPath, + fileSystem: fileSystem, + runner: scriptExec, + stderr: stderr, + onlyIfVersionChanged: false, + ), + completion(isTrue), + ); + + expect('$stderr', isEmpty); + }); +} + +final class FakeProcessRunner extends Fake implements ProcessRunner { + FakeProcessRunner(this._cannedResponses); + final Map _cannedResponses; + + @override + Future runProcess( + List commandLine, { + io.Directory? workingDirectory, + bool? printOutput, + bool failOk = false, + Stream>? stdin, + bool runInShell = false, + io.ProcessStartMode startMode = io.ProcessStartMode.normal, + }) async { + final ProcessRunnerResult? command = _cannedResponses[commandLine.join(' ')]; + if (command == null) { + fail('Unexpected process: ${commandLine.join(' ')}'); + } + return command; + } +} diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 4783525d5155c..e8c0eaf50b17f 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -6,38 +6,22 @@ homepage: https://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - args: 2.7.0 - vector_math: 2.1.4 - xml: 6.5.0 + args: any + vector_math: any + xml: any - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + meta: any dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any -# PUBSPEC CHECKSUM: b7f0 +# PUBSPEC CHECKSUM: rtbcae diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 6ef4ce2117f46..2e41bbbf4ba24 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -4,36 +4,18 @@ description: Various tests for tracing in flutter/flutter environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - vm_service: 15.0.0 + vm_service: any - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 4947 + +# PUBSPEC CHECKSUM: hi004i diff --git a/docs/infra/Experimental-Branch.md b/docs/infra/Experimental-Branch.md index c86b2e564eb93..56466ac27db1b 100644 --- a/docs/infra/Experimental-Branch.md +++ b/docs/infra/Experimental-Branch.md @@ -58,6 +58,3 @@ asynchronously (typically a few minutes, though may take longer when postsubmit queues are under load): ![Example](https://github.com/user-attachments/assets/077094b6-5f7e-4e1b-952c-2a3d1abf6f8f) - -To enable a branch for "Run all tasks", reach out to `team-infra`. It's a [bit -of a hack](https://github.com/flutter/cocoon/blob/249ffc063ddd43aec681c776a2953d5c26f294a3/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart#L64-L72) at the moment. diff --git a/docs/infra/Updating-dependencies-in-Flutter.md b/docs/infra/Updating-dependencies-in-Flutter.md index 320583be4d338..c187857596a00 100644 --- a/docs/infra/Updating-dependencies-in-Flutter.md +++ b/docs/infra/Updating-dependencies-in-Flutter.md @@ -18,4 +18,7 @@ Sometimes you need to update a single dependency as a [cherrypick to a release c In that case, you can run: -`flutter update-packages --cherry-pick-package=[pub package name] --cherry-pick-version='[pub package version]'` +`flutter update-packages --cherry-pick=[pub package name]:[pub package version],[pub package2 name]:[pub package2 version]` + +for example, to update the `test` dependencies, run +`flutter update-packages --cherry-pick=test_api:0.7.6,test_core:0.6.10,test:1.26.1` diff --git a/docs/triage/README.md b/docs/triage/README.md index f9ffc110a66ff..e51acaecfc5ca 100644 --- a/docs/triage/README.md +++ b/docs/triage/README.md @@ -83,6 +83,7 @@ In general the flow chart for team assignment is as follows, stopping as soon as - If it's about the Flutter engine, add `team-engine`. - If it's about the Flutter framework, add `team-framework`. - If it's about the Flutter tool, add `team-tool`. +- If it's about developer tools, add `team-devexp`. - If it's about a first-party package: - If it's about `go_router` or `go_router_builder`, add `team-go_router`. - If it's about `two_dimensional_scrollables`, add `team-framework`. @@ -92,7 +93,7 @@ In general the flow chart for team assignment is as follows, stopping as soon as _It is expected that some bugs will end up being re-assigned to a different team during secondary triage. If there are specific categories of issues where this always happens, the flow chart above should be updated accordingly, but having it happen occasionally is just the process working as expected; in some cases only the engineers working on an issue will know how the work is divided among teams._ -Bugs relating to the developer tools should be moved to the `flutter/devtools` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `d: devtools` label as well as the pertinent labels for where the work should occur). Issues tagged with `d: devtools` or moved to the `flutter/devtools` repo will be triaged as described by [flutter/devtools/wiki/Triage](https://github.com/flutter/devtools/wiki/Triage). +Bugs relating to the developer tools should be moved to the `flutter/devtools` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `a: devtools` label as well as the pertinent labels for where the work should occur). Issues tagged with `team-devexp` and/or `a: devtools`, or moved to the `flutter/devtools` repo, will be triaged as described by [flutter/devtools/wiki/Triage](https://github.com/flutter/devtools/wiki/Triage). Bugs relating to the IntelliJ IDEs should be moved to the `flutter/flutter-intellij` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `d: intellij` label as well as the pertinent labels for where the work should occur). Issues tagged with `d: intellij` will be reviewed by the Flutter IntelliJ team as described by [flutter/flutter-intellij/wiki/Triaging](https://github.com/flutter/flutter-intellij/wiki/Triaging). diff --git a/engine/src/build/config/BUILDCONFIG.gn b/engine/src/build/config/BUILDCONFIG.gn index 45c5fff1f3c68..aa68698383bb7 100644 --- a/engine/src/build/config/BUILDCONFIG.gn +++ b/engine/src/build/config/BUILDCONFIG.gn @@ -202,6 +202,7 @@ if (current_os == "win") { is_posix = false is_win = true is_wasm = false + is_qnx = false } else if (current_os == "mac") { is_android = false is_chromeos = false @@ -213,6 +214,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "android") { is_android = true is_chromeos = false @@ -224,6 +226,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "chromeos") { is_android = false is_chromeos = true @@ -235,6 +238,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "nacl") { # current_os == "nacl" will be passed by the nacl toolchain definition. # It is not set by default or on the command line. We treat is as a @@ -249,6 +253,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "ios") { is_android = false is_chromeos = false @@ -260,6 +265,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "linux") { is_android = false is_chromeos = false @@ -271,6 +277,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "fuchsia" || target_os == "fuchsia") { is_android = false is_chromeos = false @@ -282,6 +289,7 @@ if (current_os == "win") { is_posix = true is_win = false is_wasm = false + is_qnx = false } else if (current_os == "wasm") { is_android = false is_chromeos = false @@ -293,6 +301,19 @@ if (current_os == "win") { is_posix = false is_win = false is_wasm = true + is_qnx = false +} else if (current_os == "qnx") { + is_android = false + is_chromeos = false + is_fuchsia = false + is_fuchsia_host = false + is_ios = false + is_linux = false + is_mac = false + is_posix = false + is_win = false + is_wasm = false + is_qnx = true } is_apple = is_ios || is_mac @@ -598,6 +619,9 @@ if (custom_toolchain != "") { clang_win_version = "" host_toolchain = "//build/toolchain/wasm" set_default_toolchain("//build/toolchain/wasm") +} else if (is_qnx) { + host_toolchain = "//build/toolchain/linux:clang_$host_cpu" + set_default_toolchain("//build/toolchain/qnx") } else { assert(false, "Toolchain not set because of unknown platform.") } diff --git a/engine/src/build/config/compiler/BUILD.gn b/engine/src/build/config/compiler/BUILD.gn index 75f0dcc569b7a..7eb0314f3c63d 100644 --- a/engine/src/build/config/compiler/BUILD.gn +++ b/engine/src/build/config/compiler/BUILD.gn @@ -76,6 +76,14 @@ config("compiler") { configs += [ "//build/config/darwin:compiler" ] } + if (is_qnx) { + defines += [ + "_XOPEN_SOURCE=700", + "_QNX_SOURCE", + "SKNX_NO_SIMD", + ] + } + # In general, Windows is totally different, but all the other builds share # some common GCC configuration. This section sets up Windows and the common # GCC flags, and then we handle the other non-Windows platforms specifically @@ -104,7 +112,7 @@ config("compiler") { # Stack protection. if (is_mac) { cflags += [ "-fstack-protector-all" ] - } else if (!is_ios && !is_wasm) { + } else if (!is_ios && !is_wasm && !is_qnx) { cflags += [ "-fstack-protector", # 8 is the default, but make this explicit here so that we don't have to @@ -346,12 +354,17 @@ config("compiler") { # Linux/Android common flags setup. # --------------------------------- - if (is_linux || is_android) { + if (is_linux || is_android || is_qnx) { cflags += [ "-fPIC", - "-pipe", # Use pipes for communicating between sub-processes. Faster. ] + if (!is_qnx) { + cflags += [ + "-pipe", # Use pipes for communicating between sub-processes. Faster. + ] + } + ldflags += [ "-fPIC", "-Wl,-z,noexecstack", @@ -363,6 +376,20 @@ config("compiler") { } } + if (is_qnx) { + qnx_arch_flags = [] + if (target_cpu == "arm64") { + qnx_arch_flags += [ + "-V", + "gcc_ntoaarch64le" + ] + } else { + assert(false, "Unknown QNX architecture") + } + cflags += qnx_arch_flags + ldflags += qnx_arch_flags + } + # Linux-specific compiler flags setup. # ------------------------------------ if (is_linux) { @@ -619,6 +646,9 @@ config("runtime_library") { default_warning_flags = [] default_warning_flags_cc = [] +if (is_qnx) { + default_warning_flags_cc += [ "-fpermissive" ] +} if (is_win) { default_warning_flags += [ # Permanent. @@ -659,13 +689,18 @@ if (is_win) { default_warning_flags += [ # Enables. "-Wendif-labels", # Weird old-style text after an #endif. - "-Werror", # Warnings as errors. # Disables. "-Wno-missing-field-initializers", # "struct foo f = {0};" "-Wno-unused-parameter", # Unused function parameters. ] + if (!is_qnx) { + default_warning_flags += [ + "-Werror", # Warnings as errors. + ] + } + if (is_wasm) { default_warning_flags += [ # zlib needs this @@ -680,27 +715,32 @@ if (is_win) { default_warning_flags += [ "-Wno-unused-but-set-parameter", "-Wno-unused-but-set-variable", - "-Wno-implicit-int-float-conversion", - "-Wno-deprecated-copy", # Needed for compiling Skia with clang-12 "-Wno-psabi", ] - if (!is_android) { + if (is_clang) { + default_warning_flags += [ + "-Wno-implicit-int-float-conversion", + "-Wno-deprecated-copy", + ] + } + + if (!is_android && is_clang) { default_warning_flags += [ # Needed for nlohmann/json. "-Wno-deprecated-literal-operator", ] } - if (!is_wasm) { + if (!is_wasm && is_clang) { default_warning_flags += [ # Unqualified std::move is pretty common. "-Wno-unqualified-std-cast-call", ] } - if (!is_fuchsia) { + if (!is_fuchsia && is_clang) { default_warning_flags += [ "-Wno-non-c-typedef-for-linkage", "-Wno-range-loop-construct", @@ -728,10 +768,14 @@ config("chromium_code") { if (is_win || is_wasm) { cflags = [] } else { - cflags = [ - "-Wall", - "-Wextra", - ] + cflags = [] + + if (!is_qnx) { + cflags = [ + "-Wall", + "-Wextra", + ] + } # In Chromium code, we define __STDC_foo_MACROS in order to get the # C99 macros on Mac and Linux. diff --git a/engine/src/build/toolchain/qnx/BUILD.gn b/engine/src/build/toolchain/qnx/BUILD.gn new file mode 100644 index 0000000000000..f99ce16a606a2 --- /dev/null +++ b/engine/src/build/toolchain/qnx/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/toolchain/gcc_toolchain.gni") + +gcc_toolchain("qnx") { + asm = "qcc" + cc = "qcc" + cxx = "q++" + + readelf = "readelf" + nm = "ntoaarch64-nm" + ar = "ntoaarch64-ar" + ld = "q++" + strip = "ntoaarch64-strip" + + toolchain_cpu = "arm64" + toolchain_os = "linux" + is_clang = false +} + diff --git a/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 06a3a6f0ac2cb..9a2cfdbca36b3 100644 --- a/engine/src/flutter/.ci.yaml +++ b/engine/src/flutter/.ci.yaml @@ -30,7 +30,7 @@ platform_properties: {"dependency": "open_jdk", "version": "version:17"} ] device_type: none - os: Mac-14 + os: Mac-14|Mac-15.5 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" @@ -449,7 +449,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - name: Mac clangd recipe: engine_v2/builder @@ -478,7 +478,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - cpu=x86 - name: Mac mac_ios_engine_ddm @@ -499,28 +499,10 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - cpu=x86 - name: Linux windows_android_aot_engine - recipe: engine_v2/engine_v2 - timeout: 120 - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # https://github.com/flutter/flutter/issues/168934 - bringup: true - properties: - add_recipes_cq: "true" - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # release_build: "true" - config_name: windows_host_engine - # Do not remove(https://github.com/flutter/flutter/issues/144644) - # Scheduler will fail to get the platform - drone_dimensions: - - os=Linux - - # TODO(matanlurey): Remove and use Linux windows_host_engine. - # https://github.com/flutter/flutter/issues/168934 - - name: Windows windows_android_aot_engine recipe: engine_v2/engine_v2 timeout: 120 properties: @@ -529,28 +511,10 @@ targets: config_name: windows_android_aot_engine # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform - drone_dimensions: - - os=Windows - - - name: Linux windows_host_engine - recipe: engine_v2/engine_v2 - timeout: 120 - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # https://github.com/flutter/flutter/issues/168934 - bringup: true - properties: - add_recipes_cq: "true" - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # release_build: "true" - config_name: windows_host_engine - # Do not remove(https://github.com/flutter/flutter/issues/144644) - # Scheduler will fail to get the platform drone_dimensions: - os=Linux - # TODO(matanlurey): Remove and use Linux windows_host_engine. - # https://github.com/flutter/flutter/issues/168934 - - name: Windows windows_host_engine + - name: Linux windows_host_engine recipe: engine_v2/engine_v2 timeout: 120 properties: @@ -560,7 +524,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Windows + - os=Linux - name: Windows windows_host_engine_test recipe: engine_v2/engine_v2 diff --git a/engine/src/flutter/.gitignore b/engine/src/flutter/.gitignore index 9abe6831d2794..a06c92d3ee69e 100644 --- a/engine/src/flutter/.gitignore +++ b/engine/src/flutter/.gitignore @@ -56,7 +56,6 @@ xcuserdata # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index ef09368d7bb99..a925468d4c126 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -74,11 +74,15 @@ group("flutter") { testonly = true # Compile the engine. - public_deps = [ - ":unittests", - "//flutter/shell/platform/embedder:flutter_engine", - "//flutter/sky", - ] + public_deps = [] + + if (!is_qnx) { + public_deps = [ + ":unittests", + "//flutter/shell/platform/embedder:flutter_engine", + "//flutter/sky", + ] + } # Ensure the example for a sample embedder compiles. if (build_embedder_examples) { @@ -93,7 +97,7 @@ group("flutter") { } # If enabled, compile the SDK / snapshot. - if (!is_fuchsia) { + if (!is_fuchsia && !is_qnx) { public_deps += [ "//flutter/lib/snapshot:generate_snapshot_bins" ] if (build_engine_artifacts) { @@ -154,7 +158,7 @@ group("flutter") { } # Build the standalone Impeller library. - if (is_mac || is_linux || is_win || is_android) { + if (is_mac || is_linux || is_win || is_android || is_qnx) { public_deps += [ "//flutter/impeller/toolkit/interop:sdk" ] } diff --git a/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h b/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h index d02d0f6005c0e..770a7759bc75f 100644 --- a/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h +++ b/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h @@ -11,4 +11,5 @@ #define STDC_HEADERS 1 #define XML_CONTEXT_BYTES 1024 #define XML_DTD 1 +#define XML_GE 1 #define XML_NS 1 diff --git a/engine/src/flutter/ci/builders/linux_android_emulator.json b/engine/src/flutter/ci/builders/linux_android_emulator.json index 53a4c90cce05c..dd1c2de730edc 100644 --- a/engine/src/flutter/ci/builders/linux_android_emulator.json +++ b/engine/src/flutter/ci/builders/linux_android_emulator.json @@ -43,11 +43,11 @@ "test_dependencies": [ { "dependency": "android_virtual_device", - "version": "android_35_google_apis_x64.textpb" + "version": "android_36_google_apis_x64.textpb" }, { "dependency": "avd_cipd_version", - "version": "build_id:8733065022087935185" + "version": "build_id:8719362231152674241" } ], "contexts": [ diff --git a/engine/src/flutter/ci/builders/linux_fuchsia_tests.json b/engine/src/flutter/ci/builders/linux_fuchsia_tests.json index c466959738407..d2b446bdd4385 100644 --- a/engine/src/flutter/ci/builders/linux_fuchsia_tests.json +++ b/engine/src/flutter/ci/builders/linux_fuchsia_tests.json @@ -139,6 +139,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { @@ -184,6 +185,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { @@ -229,6 +231,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/local_engine.json b/engine/src/flutter/ci/builders/local_engine.json index 61ee3d8016a68..0c6fcfda69935 100644 --- a/engine/src/flutter/ci/builders/local_engine.json +++ b/engine/src/flutter/ci/builders/local_engine.json @@ -3,7 +3,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -70,7 +70,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -103,7 +103,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -136,7 +136,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -170,7 +170,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -206,7 +206,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -344,7 +344,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -377,7 +377,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -410,7 +410,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -494,7 +494,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -578,7 +578,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -610,7 +610,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -643,7 +643,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -676,7 +676,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -815,7 +815,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -899,7 +899,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -1037,7 +1037,7 @@ "name": "macos/wasm_release", "drone_dimensions": [ "device_type=none", - "os=Mac-14" + "os=Mac-14|Mac-15.5" ], "gclient_variables": { "download_android_deps": false, @@ -1067,7 +1067,7 @@ "name": "macos/wasm_debug_unopt", "drone_dimensions": [ "device_type=none", - "os=Mac-14" + "os=Mac-14|Mac-15.5" ], "gclient_variables": { "download_android_deps": false, diff --git a/engine/src/flutter/ci/builders/mac_android_aot_engine.json b/engine/src/flutter/ci/builders/mac_android_aot_engine.json index 17b794d4beaf5..05cb1c6888cad 100644 --- a/engine/src/flutter/ci/builders/mac_android_aot_engine.json +++ b/engine/src/flutter/ci/builders/mac_android_aot_engine.json @@ -22,7 +22,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -80,7 +80,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -140,7 +140,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -200,7 +200,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -258,7 +258,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -318,7 +318,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_clang_tidy.json b/engine/src/flutter/ci/builders/mac_clang_tidy.json index 29ff251b9658b..b3928b3dc358a 100644 --- a/engine/src/flutter/ci/builders/mac_clang_tidy.json +++ b/engine/src/flutter/ci/builders/mac_clang_tidy.json @@ -3,7 +3,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -74,7 +74,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -129,7 +129,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -184,7 +184,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -239,7 +239,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -294,7 +294,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_host_engine.json b/engine/src/flutter/ci/builders/mac_host_engine.json index c8288e1c0ddc1..a0c6e3a09444e 100644 --- a/engine/src/flutter/ci/builders/mac_host_engine.json +++ b/engine/src/flutter/ci/builders/mac_host_engine.json @@ -18,7 +18,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -85,7 +85,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -141,7 +141,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -206,7 +206,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -257,7 +257,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -308,7 +308,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -371,7 +371,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -425,7 +425,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -478,7 +478,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -544,7 +544,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -601,7 +601,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -657,7 +657,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -723,7 +723,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -778,7 +778,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -833,7 +833,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -900,7 +900,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -958,7 +958,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -1015,7 +1015,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_ios_engine.json b/engine/src/flutter/ci/builders/mac_ios_engine.json index 1f264d9acb1d4..d16167cdca947 100644 --- a/engine/src/flutter/ci/builders/mac_ios_engine.json +++ b/engine/src/flutter/ci/builders/mac_ios_engine.json @@ -15,7 +15,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -62,7 +62,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -111,7 +111,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -158,7 +158,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -205,7 +205,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -252,7 +252,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -301,7 +301,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -352,7 +352,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -401,7 +401,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -450,7 +450,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json b/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json index 660da9467ae49..e3a39b920bbb1 100644 --- a/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json +++ b/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json @@ -15,7 +15,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -64,7 +64,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -115,7 +115,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -164,7 +164,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_unopt.json b/engine/src/flutter/ci/builders/mac_unopt.json index 7b964cbce1018..056a9dd5cf769 100644 --- a/engine/src/flutter/ci/builders/mac_unopt.json +++ b/engine/src/flutter/ci/builders/mac_unopt.json @@ -4,7 +4,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -57,7 +57,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -108,7 +108,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -165,7 +165,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -224,7 +224,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -281,7 +281,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -350,7 +350,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -418,7 +418,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/licenses.sh b/engine/src/flutter/ci/licenses.sh index 67f1290f2b3ae..a50e4e54b9f3b 100755 --- a/engine/src/flutter/ci/licenses.sh +++ b/engine/src/flutter/ci/licenses.sh @@ -191,7 +191,7 @@ function verify_licenses() ( local actualLicenseCount actualLicenseCount="$(tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9')" - local expectedLicenseCount=846 + local expectedLicenseCount=848 if [[ $actualLicenseCount -ne $expectedLicenseCount ]]; then echo "=============================== ERROR ===============================" diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index ac78b4d2afea6..d6c6f639e005d 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -191,6 +191,7 @@ ../../../flutter/impeller/renderer/backend/gles/test ../../../flutter/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc ../../../flutter/impeller/renderer/backend/metal/allocator_mtl_unittests.mm +../../../flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk_unittests.cc @@ -1729,7 +1730,7 @@ ../../../flutter/third_party/expat/.mailmap ../../../flutter/third_party/expat/Brewfile ../../../flutter/third_party/expat/README.md -../../../flutter/third_party/expat/appveyor.yml +../../../flutter/third_party/expat/SECURITY.md ../../../flutter/third_party/expat/expat/.clang-format ../../../flutter/third_party/expat/expat/.gitignore ../../../flutter/third_party/expat/expat/AUTHORS @@ -1747,6 +1748,8 @@ ../../../flutter/third_party/expat/expat/conftools/ax-append-link-flags.m4 ../../../flutter/third_party/expat/expat/conftools/ax-check-compile-flag.m4 ../../../flutter/third_party/expat/expat/conftools/ax-check-link-flag.m4 +../../../flutter/third_party/expat/expat/conftools/ax-cxx-compile-stdcxx-11.m4 +../../../flutter/third_party/expat/expat/conftools/ax-cxx-compile-stdcxx.m4 ../../../flutter/third_party/expat/expat/conftools/ax-require-defined.m4 ../../../flutter/third_party/expat/expat/conftools/expat.m4 ../../../flutter/third_party/expat/expat/conftools/expatcfg-compiler-supports-visibility.m4 @@ -1758,12 +1761,14 @@ ../../../flutter/third_party/expat/expat/gennmtab/.gitignore ../../../flutter/third_party/expat/expat/lib/.gitignore ../../../flutter/third_party/expat/expat/lib/libexpat.def.cmake +../../../flutter/third_party/expat/expat/m4/.gitignore ../../../flutter/third_party/expat/expat/memory-sanitizer-blacklist.txt ../../../flutter/third_party/expat/expat/tests ../../../flutter/third_party/expat/expat/win32/.gitignore ../../../flutter/third_party/expat/expat/win32/MANIFEST.txt ../../../flutter/third_party/expat/expat/win32/README.txt ../../../flutter/third_party/expat/expat/win32/expat.iss +../../../flutter/third_party/expat/expat/win32/version.rc.cmake ../../../flutter/third_party/expat/expat/xmlwf/.gitignore ../../../flutter/third_party/expat/expat/xmlwf/xmlwf_helpgen.py ../../../flutter/third_party/expat/testdata diff --git a/engine/src/flutter/ci/licenses_golden/licenses_dart b/engine/src/flutter/ci/licenses_golden/licenses_dart index deb38a98bcbfc..221a87a79e880 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_dart +++ b/engine/src/flutter/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 98bc8f2531a06f3e56ce2915e1ed97c6 +Signature: 2591f3317de57e46f76db0672648ff78 ==================================================================================================== LIBRARY: dart @@ -361,10 +361,7 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/resolver.cc + ../../../flut ORIGIN: ../../../flutter/third_party/dart/runtime/vm/resolver.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_arm.cc + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_ia32.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_list.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_x64.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stack_frame.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stub_code.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/timer.cc + ../../../flutter/third_party/dart/LICENSE @@ -437,10 +434,7 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/resolver.cc FILE: ../../../flutter/third_party/dart/runtime/vm/resolver.h FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry.cc FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry.h -FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_arm.cc -FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_ia32.cc FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_list.h -FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_x64.cc FILE: ../../../flutter/third_party/dart/runtime/vm/stack_frame.h FILE: ../../../flutter/third_party/dart/runtime/vm/stub_code.h FILE: ../../../flutter/third_party/dart/runtime/vm/timer.cc @@ -1934,7 +1928,6 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.h + ../../.. ORIGIN: ../../../flutter/third_party/dart/runtime/vm/report.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/report.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/ring_buffer.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_arm64.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stack_frame_arm64.h + ../../../flutter/third_party/dart/LICENSE @@ -2026,7 +2019,6 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/regexp/unibrow.h FILE: ../../../flutter/third_party/dart/runtime/vm/report.cc FILE: ../../../flutter/third_party/dart/runtime/vm/report.h FILE: ../../../flutter/third_party/dart/runtime/vm/ring_buffer.h -FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_arm64.cc FILE: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.cc FILE: ../../../flutter/third_party/dart/runtime/vm/simulator_arm64.h FILE: ../../../flutter/third_party/dart/runtime/vm/stack_frame_arm64.h @@ -3570,7 +3562,6 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/vm/object_graph_copy.cc + ../. ORIGIN: ../../../flutter/third_party/dart/runtime/vm/object_graph_copy.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/pending_deopts.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/pending_deopts.h + ../../../flutter/third_party/dart/LICENSE -ORIGIN: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_riscv.cc + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/stack_frame_riscv.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/thread_interrupter_android_arm.S + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/virtual_memory_compressed.cc + ../../../flutter/third_party/dart/LICENSE @@ -3614,7 +3605,6 @@ FILE: ../../../flutter/third_party/dart/runtime/vm/object_graph_copy.cc FILE: ../../../flutter/third_party/dart/runtime/vm/object_graph_copy.h FILE: ../../../flutter/third_party/dart/runtime/vm/pending_deopts.cc FILE: ../../../flutter/third_party/dart/runtime/vm/pending_deopts.h -FILE: ../../../flutter/third_party/dart/runtime/vm/runtime_entry_riscv.cc FILE: ../../../flutter/third_party/dart/runtime/vm/stack_frame_riscv.h FILE: ../../../flutter/third_party/dart/runtime/vm/thread_interrupter_android_arm.S FILE: ../../../flutter/third_party/dart/runtime/vm/virtual_memory_compressed.cc @@ -4232,6 +4222,8 @@ ORIGIN: ../../../flutter/third_party/dart/runtime/engine/include/dart_engine.h + ORIGIN: ../../../flutter/third_party/dart/runtime/observatory/lib/src/elements/helpers/element_utils.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/platform/list_queue.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/platform/lockers.h + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart + ../../../flutter/third_party/dart/LICENSE +ORIGIN: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/tools/generate_dart_api_win_c.dart + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/dwarf_so_writer.h + ../../../flutter/third_party/dart/LICENSE ORIGIN: ../../../flutter/third_party/dart/runtime/vm/mach_o.cc + ../../../flutter/third_party/dart/LICENSE @@ -4252,6 +4244,8 @@ FILE: ../../../flutter/third_party/dart/runtime/engine/include/dart_engine.h FILE: ../../../flutter/third_party/dart/runtime/observatory/lib/src/elements/helpers/element_utils.dart FILE: ../../../flutter/third_party/dart/runtime/platform/list_queue.h FILE: ../../../flutter/third_party/dart/runtime/platform/lockers.h +FILE: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer_dart2js.dart +FILE: ../../../flutter/third_party/dart/runtime/tools/dartfuzz/flag_fuzzer_dart2wasm.dart FILE: ../../../flutter/third_party/dart/runtime/tools/generate_dart_api_win_c.dart FILE: ../../../flutter/third_party/dart/runtime/vm/dwarf_so_writer.h FILE: ../../../flutter/third_party/dart/runtime/vm/mach_o.cc @@ -4880,7 +4874,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/6aeb798bdbe27e6e6c5ee533dca392404ca496ce +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/239174405ad089da5f6063c8c002efbbd354b0b0 /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 5af61b2dc25e4..e6fc889d9e26b 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1281,8 +1281,6 @@ ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutte ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/stack_line_reader.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/string_view.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/utils/list_cpu_features.c -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parse_fuzzer.c -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parsebuffer_fuzzer.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/conan/test_package/test_package.cpp ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/grpc/src/compiler/java_generator.cc @@ -4101,6 +4099,8 @@ ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutt ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/tool.cc ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/transport_common.cc ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/transport_common.h +ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parse_fuzzer.c +ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parsebuffer_fuzzer.c ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/wuffs/release/c/wuffs-v0.2.c ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/wuffs/release/c/wuffs-v0.3.c TYPE: LicenseType.apache @@ -42335,11 +42335,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2000-2005 Fred L. Drake, Jr. Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Cristian Rodríguez Copyright (c) 2016 Thomas Beutlich Copyright (c) 2017 Rhodri James Copyright (c) 2022 Thijs Schreijer +Copyright (c) 2023 Hanno Böck +Copyright (c) 2023 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -42376,7 +42379,7 @@ Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie Copyright (c) 2016 Eric Rahm -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Gaurav Copyright (c) 2016 Thomas Beutlich Copyright (c) 2016 Gustavo Grieco @@ -42395,10 +42398,15 @@ Copyright (c) 2018 Mariusz Zaborski Copyright (c) 2019 David Loffredo Copyright (c) 2019-2020 Ben Wagner Copyright (c) 2019 Vadim Zeitlin -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton Copyright (c) 2022 Jann Horn +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Owain Davies +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024-2025 Berkay Eren Ürün +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -42469,7 +42477,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Don Lewis Copyright (c) 2017 Rhodri James @@ -42477,8 +42485,10 @@ Copyright (c) 2017 Alexander Bluhm Copyright (c) 2017 Benbuck Nason Copyright (c) 2017 José Gutiérrez de la Concha Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Hanno Böck Licensed under the MIT license: @@ -42513,13 +42523,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2004-2009 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo Copyright (c) 2020 Joe Orton Copyright (c) 2020 Kleber Tarcísio Copyright (c) 2021 Tim Bray Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride Licensed under the MIT license: @@ -42556,6 +42567,8 @@ Copyright (c) 2002-2009 Karl Waclawek Copyright (c) 2016-2017 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2017 Franek Korta +Copyright (c) 2022 Sean McBride +Copyright (c) 2025 Hanno Böck Licensed under the MIT license: @@ -42589,7 +42602,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2002-2005 Karl Waclawek -Copyright (c) 2016-2017 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2017 Rhodri James Licensed under the MIT license: @@ -42664,7 +42677,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2005 Karl Waclawek -Copyright (c) 2016-2019 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Licensed under the MIT license: @@ -42725,11 +42738,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== LIBRARY: expat -ORIGIN: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c ORIGIN: ../../../flutter/third_party/expat/expat/xmlwf/codepage.h ORIGIN: ../../../flutter/third_party/expat/expat/xmlwf/filemap.h TYPE: LicenseType.mit -FILE: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c FILE: ../../../flutter/third_party/expat/expat/xmlwf/codepage.h FILE: ../../../flutter/third_party/expat/expat/xmlwf/filemap.h ---------------------------------------------------------------------------------------------------- @@ -42794,6 +42805,39 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: expat +ORIGIN: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c +TYPE: LicenseType.mit +FILE: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c +---------------------------------------------------------------------------------------------------- +Copyright (c) 1997-2000 Thai Open Source Software Center Ltd +Copyright (c) 2000 Clark Cooper +Copyright (c) 2002 Fred L. Drake, Jr. +Copyright (c) 2016-2024 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +==================================================================================================== + ==================================================================================================== LIBRARY: expat ORIGIN: ../../../flutter/third_party/expat/expat/lib/asciitab.h @@ -42880,10 +42924,10 @@ Copyright (c) 2002 Greg Stein Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Licensed under the MIT license: @@ -42917,7 +42961,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Karl Waclawek Copyright (c) 2002 Fred L. Drake, Jr. -Copyright (c) 2017 Sebastian Pipping +Copyright (c) 2017-2024 Sebastian Pipping Licensed under the MIT license: @@ -42952,10 +42996,11 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2004-2006 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -43312,10 +43357,9 @@ ORIGIN: ../../../flutter/third_party/expat/expat/COPYING TYPE: LicenseType.mit FILE: ../../../flutter/third_party/expat/expat/expat.pc.in FILE: ../../../flutter/third_party/expat/expat/lib/siphash.h -FILE: ../../../flutter/third_party/expat/expat/win32/version.rc ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -43456,7 +43500,8 @@ FILE: ../../../flutter/third_party/expat/expat/lib/winconfig.h Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Greg Stein Copyright (c) 2005 Karl Waclawek -Copyright (c) 2017-2021 Sebastian Pipping +Copyright (c) 2017-2023 Sebastian Pipping +Copyright (c) 2023 Orgad Shaneh Licensed under the MIT license: @@ -44098,9 +44143,11 @@ FILE: ../../../flutter/third_party/expat/expat/lib/internal.h Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -48532,6 +48579,39 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: expat +ORIGIN: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.cpp +ORIGIN: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.proto +TYPE: LicenseType.mit +FILE: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.cpp +FILE: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.proto +---------------------------------------------------------------------------------------------------- +Copyright (c) 2022 Mark Brand +Copyright (c) 2025 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +==================================================================================================== + ==================================================================================================== LIBRARY: pkg ORIGIN: ../../../flutter/third_party/pkg/coverage/benchmark/many_isolates.dart + ../../../flutter/third_party/pkg/coverage/LICENSE @@ -51009,6 +51089,7 @@ ORIGIN: ../../../flutter/fml/platform/posix/native_library_posix.cc + ../../../f ORIGIN: ../../../flutter/fml/platform/posix/paths_posix.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/posix/posix_wrappers_posix.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/posix/process_posix.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/qnx/paths_qnx.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/win/command_line_win.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/win/errors_win.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/win/errors_win.h + ../../../flutter/LICENSE @@ -51292,6 +51373,8 @@ ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.cc + ../../../flutte ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/arc_geometry.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/arc_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/circle_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/circle_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/cover_geometry.cc + ../../../flutter/LICENSE @@ -52778,12 +52861,14 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHead ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionCollection.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionCollectionTest.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FakeUIPressProxy.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h + ../../../flutter/LICENSE @@ -52814,6 +52899,9 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeySe ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayerTest.mm + ../../../flutter/LICENSE @@ -52833,6 +52921,7 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlugi ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPluginTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h + ../../../flutter/LICENSE @@ -53252,6 +53341,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor.h + ../../../flutter ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_opengl.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_opengl.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_opengl_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_software.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_software.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_compositor_software_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_private.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc + ../../../flutter/LICENSE @@ -54018,6 +54110,7 @@ FILE: ../../../flutter/fml/platform/posix/native_library_posix.cc FILE: ../../../flutter/fml/platform/posix/paths_posix.cc FILE: ../../../flutter/fml/platform/posix/posix_wrappers_posix.cc FILE: ../../../flutter/fml/platform/posix/process_posix.cc +FILE: ../../../flutter/fml/platform/qnx/paths_qnx.cc FILE: ../../../flutter/fml/platform/win/command_line_win.cc FILE: ../../../flutter/fml/platform/win/errors_win.cc FILE: ../../../flutter/fml/platform/win/errors_win.h @@ -54301,6 +54394,8 @@ FILE: ../../../flutter/impeller/entity/entity_pass_target.cc FILE: ../../../flutter/impeller/entity/entity_pass_target.h FILE: ../../../flutter/impeller/entity/entity_playground.cc FILE: ../../../flutter/impeller/entity/entity_playground.h +FILE: ../../../flutter/impeller/entity/geometry/arc_geometry.cc +FILE: ../../../flutter/impeller/entity/geometry/arc_geometry.h FILE: ../../../flutter/impeller/entity/geometry/circle_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/circle_geometry.h FILE: ../../../flutter/impeller/entity/geometry/cover_geometry.cc @@ -55808,6 +55903,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadle FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/PrivacyInfo.xcprivacy @@ -55816,6 +55912,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionColl FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FakeUIPressProxy.swift FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h @@ -55846,6 +55943,9 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeySeco FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayerTest.mm @@ -55865,6 +55965,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginA FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPluginTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h @@ -56297,6 +56398,9 @@ FILE: ../../../flutter/shell/platform/linux/fl_compositor.h FILE: ../../../flutter/shell/platform/linux/fl_compositor_opengl.cc FILE: ../../../flutter/shell/platform/linux/fl_compositor_opengl.h FILE: ../../../flutter/shell/platform/linux/fl_compositor_opengl_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_compositor_software.cc +FILE: ../../../flutter/shell/platform/linux/fl_compositor_software.h +FILE: ../../../flutter/shell/platform/linux/fl_compositor_software_test.cc FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc @@ -79089,4 +79193,4 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. ==================================================================================================== -Total license count: 846 +Total license count: 848 diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index 0cec841153784..dee5aaaddf8d6 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 6cf3b02f62f4fa04c4db32736c7dd291 +Signature: 90fec2d48e1e93bcb059f4f4abe931f9 ==================================================================================================== LIBRARY: fuchsia_sdk @@ -6928,7 +6928,7 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/inspect/vmo/state.cc + ../../../fuchsia/s ORIGIN: ../../../fuchsia/sdk/linux/pkg/inspect/vmo/types.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/media_cpp/include/lib/media/cpp/type_converters.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/media_cpp/type_converters.cc + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/memory_barriers/include/src/lib/memory_barriers/memory_barriers.h + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/memory_barriers/include/lib/memory_barriers/memory_barriers.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/mmio/include/lib/mmio/mmio.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/mmio/mmio-buffer.cc + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_token_pair.cc + ../../../fuchsia/sdk/linux/LICENSE @@ -7276,7 +7276,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/inspect/vmo/state.cc FILE: ../../../fuchsia/sdk/linux/pkg/inspect/vmo/types.cc FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp/include/lib/media/cpp/type_converters.h FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp/type_converters.cc -FILE: ../../../fuchsia/sdk/linux/pkg/memory_barriers/include/src/lib/memory_barriers/memory_barriers.h +FILE: ../../../fuchsia/sdk/linux/pkg/memory_barriers/include/lib/memory_barriers/memory_barriers.h FILE: ../../../fuchsia/sdk/linux/pkg/mmio/include/lib/mmio/mmio.h FILE: ../../../fuchsia/sdk/linux/pkg/mmio/mmio-buffer.cc FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_token_pair.cc @@ -12101,8 +12101,6 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/magma_client/include/lib/magma/magma_sysm ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_ref_pair.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_token_pair.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_ref_pair.cc + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/constructors.h + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/storage.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/utility.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/string_view.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/utility.h + ../../../fuchsia/sdk/linux/LICENSE @@ -12504,8 +12502,6 @@ FILE: ../../../fuchsia/sdk/linux/pkg/magma_client/include/lib/magma/magma_sysmem FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_ref_pair.h FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_token_pair.h FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_ref_pair.cc -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/constructors.h -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/storage.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/utility.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/string_view.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/utility.h @@ -14399,6 +14395,8 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/collector.shard. ORIGIN: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/bind.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/snapshot.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/stats.h + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/inspect/bounded_list_node.cc + ../../../fuchsia/sdk/linux/LICENSE +ORIGIN: ../../../fuchsia/sdk/linux/pkg/inspect/include/lib/inspect/cpp/bounded_list_node.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/mmio/include/lib/mmio/mmio-ops.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/sync_cpp/include/lib/sync/cpp/mutex.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/sys_service_cpp/service_handler.cc + ../../../fuchsia/sdk/linux/LICENSE @@ -14506,6 +14504,8 @@ FILE: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/collector.shard.cm FILE: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/bind.h FILE: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/snapshot.h FILE: ../../../fuchsia/sdk/linux/pkg/heapdump_instrumentation/include/heapdump/stats.h +FILE: ../../../fuchsia/sdk/linux/pkg/inspect/bounded_list_node.cc +FILE: ../../../fuchsia/sdk/linux/pkg/inspect/include/lib/inspect/cpp/bounded_list_node.h FILE: ../../../fuchsia/sdk/linux/pkg/mmio/include/lib/mmio/mmio-ops.h FILE: ../../../fuchsia/sdk/linux/pkg/sync_cpp/include/lib/sync/cpp/mutex.h FILE: ../../../fuchsia/sdk/linux/pkg/sys_service_cpp/service_handler.cc diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index c37a342db8877..73c4257d089b8 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: aebc333eca857a2ca876b998e04ccf66 +Signature: 5d2a6018aed55b67bf6189f800d5f9b9 ==================================================================================================== LIBRARY: etc1 @@ -434,6 +434,8 @@ FILE: ../../../flutter/third_party/skia/modules/pathkit/perf/pathops.bench.js FILE: ../../../flutter/third_party/skia/modules/pathkit/perf/perfReporter.js FILE: ../../../flutter/third_party/skia/modules/skparagraph/test.html FILE: ../../../flutter/third_party/skia/package-lock.json +FILE: ../../../flutter/third_party/skia/relnotes/fontconfig.md +FILE: ../../../flutter/third_party/skia/relnotes/macos1015.md FILE: ../../../flutter/third_party/skia/src/gpu/gpu_workaround_list.txt FILE: ../../../flutter/third_party/skia/src/ports/fontations/Cargo.toml FILE: ../../../flutter/third_party/skia/src/sksl/generated/sksl_compute.minified.sksl @@ -9895,6 +9897,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia +ORIGIN: ../../../flutter/third_party/skia/gm/hdr_pip_blur.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkCPUContext.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkCPURecorder.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkRecorder.h + ../../../flutter/third_party/skia/LICENSE @@ -9925,7 +9928,9 @@ ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/Precompile ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontconfig_freetype.cpp + ../../../flutter/third_party/skia/LICENSE TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/skia/gm/hdr_pip_blur.cpp FILE: ../../../flutter/third_party/skia/include/core/SkCPUContext.h FILE: ../../../flutter/third_party/skia/include/core/SkCPURecorder.h FILE: ../../../flutter/third_party/skia/include/core/SkRecorder.h @@ -9956,6 +9961,7 @@ FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/PrecompileIm FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.cpp FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.h FILE: ../../../flutter/third_party/skia/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp +FILE: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontconfig_freetype.cpp ---------------------------------------------------------------------------------------------------- Copyright 2025 Google LLC diff --git a/engine/src/flutter/display_list/BUILD.gn b/engine/src/flutter/display_list/BUILD.gn index be2065977b3ea..6e78eb17be4e8 100644 --- a/engine/src/flutter/display_list/BUILD.gn +++ b/engine/src/flutter/display_list/BUILD.gn @@ -280,36 +280,38 @@ if (enable_unittests) { } } -source_set("display_list_benchmarks_source") { - testonly = true +if (enable_unittests) { + source_set("display_list_benchmarks_source") { + testonly = true - sources = [ - "benchmarking/dl_benchmarks.cc", - "benchmarking/dl_benchmarks.h", - ] + sources = [ + "benchmarking/dl_benchmarks.cc", + "benchmarking/dl_benchmarks.h", + ] - deps = [ - ":display_list", - ":display_list_fixtures", - "$dart_src/runtime:libdart_jit", # for tracing - "//flutter/benchmarking", - "//flutter/common/graphics", - "//flutter/display_list/testing:display_list_surface_provider", - "//flutter/display_list/testing:display_list_testing", - "//flutter/fml", - "//flutter/skia", - "//flutter/testing:skia", - "//flutter/testing:testing_lib", - ] -} + deps = [ + ":display_list", + ":display_list_fixtures", + "$dart_src/runtime:libdart_jit", # for tracing + "//flutter/benchmarking", + "//flutter/common/graphics", + "//flutter/display_list/testing:display_list_surface_provider", + "//flutter/display_list/testing:display_list_testing", + "//flutter/fml", + "//flutter/skia", + "//flutter/testing:skia", + "//flutter/testing:testing_lib", + ] + } -executable("display_list_benchmarks") { - testonly = true + executable("display_list_benchmarks") { + testonly = true - deps = [ ":display_list_benchmarks_source" ] + deps = [ ":display_list_benchmarks_source" ] + } } -if (is_ios) { +if (is_ios && enable_unittests) { shared_library("ios_display_list_benchmarks") { testonly = true visibility = [ ":*" ] diff --git a/engine/src/flutter/display_list/benchmarking/dl_complexity_helper.h b/engine/src/flutter/display_list/benchmarking/dl_complexity_helper.h index 2fe856c1cc63d..83a98798490c2 100644 --- a/engine/src/flutter/display_list/benchmarking/dl_complexity_helper.h +++ b/engine/src/flutter/display_list/benchmarking/dl_complexity_helper.h @@ -8,6 +8,7 @@ #include "flutter/display_list/benchmarking/dl_complexity.h" #include "flutter/display_list/dl_blend_mode.h" #include "flutter/display_list/dl_op_receiver.h" +#include "flutter/display_list/geometry/dl_path.h" #include "flutter/display_list/utils/dl_receiver_utils.h" namespace flutter { diff --git a/engine/src/flutter/display_list/display_list.cc b/engine/src/flutter/display_list/display_list.cc index 3e5505b8f7882..0f032aa07edd7 100644 --- a/engine/src/flutter/display_list/display_list.cc +++ b/engine/src/flutter/display_list/display_list.cc @@ -6,6 +6,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_op_records.h" +#include "flutter/display_list/geometry/dl_path.h" #include "flutter/fml/trace_event.h" namespace flutter { diff --git a/engine/src/flutter/display_list/dl_color.h b/engine/src/flutter/display_list/dl_color.h index 51d32bce93317..174521f378f9a 100644 --- a/engine/src/flutter/display_list/dl_color.h +++ b/engine/src/flutter/display_list/dl_color.h @@ -61,7 +61,7 @@ struct DlColor { return DlColor(a, r, g, b, DlColorSpace::kSRGB); } - static constexpr uint8_t toAlpha(DlScalar opacity) { return toC(opacity); } + static inline uint8_t toAlpha(DlScalar opacity) { return toC(opacity); } static constexpr DlScalar toOpacity(uint8_t alpha) { return toF(alpha); } // clang-format off @@ -99,16 +99,16 @@ struct DlColor { ///\deprecated Use floating point accessors to avoid data loss when using wide /// gamut colors. - constexpr int getAlpha() const { return toC(alpha_); } + inline int getAlpha() const { return toC(alpha_); } ///\deprecated Use floating point accessors to avoid data loss when using wide /// gamut colors. - constexpr int getRed() const { return toC(red_); } + inline int getRed() const { return toC(red_); } ///\deprecated Use floating point accessors to avoid data loss when using wide /// gamut colors. - constexpr int getGreen() const { return toC(green_); } + inline int getGreen() const { return toC(green_); } ///\deprecated Use floating point accessors to avoid data loss when using wide /// gamut colors. - constexpr int getBlue() const { return toC(blue_); } + inline int getBlue() const { return toC(blue_); } constexpr DlScalar getAlphaF() const { return alpha_; } constexpr DlScalar getRedF() const { return red_; } @@ -117,16 +117,16 @@ struct DlColor { constexpr DlColorSpace getColorSpace() const { return color_space_; } - constexpr DlColor withAlpha(uint8_t alpha) const { // + inline DlColor withAlpha(uint8_t alpha) const { // return DlColor((argb() & 0x00FFFFFF) | (alpha << 24)); } - constexpr DlColor withRed(uint8_t red) const { // + inline DlColor withRed(uint8_t red) const { // return DlColor((argb() & 0xFF00FFFF) | (red << 16)); } - constexpr DlColor withGreen(uint8_t green) const { // + inline DlColor withGreen(uint8_t green) const { // return DlColor((argb() & 0xFFFF00FF) | (green << 8)); } - constexpr DlColor withBlue(uint8_t blue) const { // + inline DlColor withBlue(uint8_t blue) const { // return DlColor((argb() & 0xFFFFFF00) | (blue << 0)); } constexpr DlColor withAlphaF(float alpha) const { // @@ -155,7 +155,7 @@ struct DlColor { ///\deprecated Use floating point accessors to avoid data loss when using wide /// gamut colors. - constexpr uint32_t argb() const { + inline uint32_t argb() const { return toC(alpha_) << 24 | // toC(red_) << 16 | // toC(green_) << 8 | // @@ -190,7 +190,7 @@ struct DlColor { DlColorSpace color_space_; static constexpr DlScalar toF(uint8_t comp) { return comp * (1.0f / 255); } - static constexpr uint8_t toC(DlScalar fComp) { return round(fComp * 255); } + static inline uint8_t toC(DlScalar fComp) { return std::round(fComp * 255); } }; } // namespace flutter diff --git a/engine/src/flutter/display_list/dl_op_receiver.h b/engine/src/flutter/display_list/dl_op_receiver.h index 0d65bad7e0c80..674e9816f2b41 100644 --- a/engine/src/flutter/display_list/dl_op_receiver.h +++ b/engine/src/flutter/display_list/dl_op_receiver.h @@ -7,15 +7,18 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_blend_mode.h" -#include "flutter/display_list/dl_canvas.h" #include "flutter/display_list/dl_paint.h" #include "flutter/display_list/dl_sampling_options.h" +#include "flutter/display_list/dl_types.h" #include "flutter/display_list/dl_vertices.h" #include "flutter/display_list/effects/dl_color_filter.h" #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/effects/dl_image_filter.h" #include "flutter/display_list/effects/dl_mask_filter.h" +#include "flutter/display_list/geometry/dl_path.h" #include "flutter/display_list/image/dl_image.h" +#include "flutter/impeller/typographer/text_frame.h" +#include "flutter/third_party/skia/include/core/SkTextBlob.h" namespace flutter { diff --git a/engine/src/flutter/display_list/dl_vertices.h b/engine/src/flutter/display_list/dl_vertices.h index 653fa9202be91..a4cffa391af66 100644 --- a/engine/src/flutter/display_list/dl_vertices.h +++ b/engine/src/flutter/display_list/dl_vertices.h @@ -83,7 +83,7 @@ class DlVertices { uint32_t mask = 0; inline Flags operator|(const Flags& rhs) const { - return {.mask = (mask | rhs.mask)}; + return Flags{.mask = (mask | rhs.mask)}; } inline Flags& operator|=(const Flags& rhs) { diff --git a/engine/src/flutter/display_list/geometry/dl_geometry_conversions.h b/engine/src/flutter/display_list/geometry/dl_geometry_conversions.h index a799076bcb3d8..02753f2d71cb5 100644 --- a/engine/src/flutter/display_list/geometry/dl_geometry_conversions.h +++ b/engine/src/flutter/display_list/geometry/dl_geometry_conversions.h @@ -78,7 +78,7 @@ inline const DlRoundRect ToDlRoundRect(const SkRRect& rrect) { }); } -inline constexpr DlMatrix ToDlMatrix(const SkMatrix& matrix) { +inline DlMatrix ToDlMatrix(const SkMatrix& matrix) { // clang-format off return DlMatrix::MakeColumn( matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY], 0.0f, matrix[SkMatrix::kMPersp0], @@ -89,7 +89,7 @@ inline constexpr DlMatrix ToDlMatrix(const SkMatrix& matrix) { // clang-format on } -inline constexpr DlMatrix ToDlMatrix(const SkM44& matrix) { +inline DlMatrix ToDlMatrix(const SkM44& matrix) { DlMatrix dl_matrix; matrix.getColMajor(dl_matrix.m); return dl_matrix; @@ -172,18 +172,17 @@ inline const SkRRect ToSkRRect(const DlRoundRect& round_rect) { // // Skia does not support rounded superellipses directly, so rendering // `DlRoundSuperellipses` on Skia requires falling back to RRect. -inline constexpr const SkRRect ToApproximateSkRRect( - const DlRoundSuperellipse& rse) { +inline const SkRRect ToApproximateSkRRect(const DlRoundSuperellipse& rse) { return ToSkRRect(rse.ToApproximateRoundRect()); }; -inline constexpr SkMatrix ToSkMatrix(const DlMatrix& matrix) { +inline SkMatrix ToSkMatrix(const DlMatrix& matrix) { return SkMatrix::MakeAll(matrix.m[0], matrix.m[4], matrix.m[12], // matrix.m[1], matrix.m[5], matrix.m[13], // matrix.m[3], matrix.m[7], matrix.m[15]); } -inline constexpr SkM44 ToSkM44(const DlMatrix& matrix) { +inline SkM44 ToSkM44(const DlMatrix& matrix) { return SkM44::ColMajor(matrix.m); } diff --git a/engine/src/flutter/display_list/geometry/dl_path_builder.cc b/engine/src/flutter/display_list/geometry/dl_path_builder.cc index 973128d29cb0d..7f78c7d48118c 100644 --- a/engine/src/flutter/display_list/geometry/dl_path_builder.cc +++ b/engine/src/flutter/display_list/geometry/dl_path_builder.cc @@ -115,7 +115,7 @@ DlPathBuilder& DlPathBuilder::AddRoundSuperellipse( BuilderReceiver receiver(*this); impeller::RoundSuperellipseParam::MakeBoundsRadii(rse.GetBounds(), rse.GetRadii()) - .AddToPath(receiver); + .Dispatch(receiver); return *this; } diff --git a/engine/src/flutter/display_list/skia/dl_sk_dispatcher.cc b/engine/src/flutter/display_list/skia/dl_sk_dispatcher.cc index b466a05a7b390..9d6988be0e138 100644 --- a/engine/src/flutter/display_list/skia/dl_sk_dispatcher.cc +++ b/engine/src/flutter/display_list/skia/dl_sk_dispatcher.cc @@ -7,6 +7,7 @@ #include "flutter/display_list/skia/dl_sk_dispatcher.h" #include "flutter/display_list/dl_blend_mode.h" +#include "flutter/display_list/dl_canvas.h" #include "flutter/display_list/effects/image_filters/dl_blur_image_filter.h" #include "flutter/display_list/geometry/dl_geometry_conversions.h" #include "flutter/display_list/skia/dl_sk_conversions.h" diff --git a/engine/src/flutter/display_list/utils/dl_matrix_clip_tracker.h b/engine/src/flutter/display_list/utils/dl_matrix_clip_tracker.h index 73a3202091448..0a1b4aa1ec211 100644 --- a/engine/src/flutter/display_list/utils/dl_matrix_clip_tracker.h +++ b/engine/src/flutter/display_list/utils/dl_matrix_clip_tracker.h @@ -8,6 +8,7 @@ #include #include "flutter/display_list/dl_canvas.h" +#include "flutter/display_list/dl_types.h" #include "flutter/display_list/geometry/dl_geometry_types.h" #include "flutter/fml/logging.h" diff --git a/engine/src/flutter/docs/contributing/Setting-up-the-Engine-development-environment.md b/engine/src/flutter/docs/contributing/Setting-up-the-Engine-development-environment.md index d7caebaa41b31..e808bb771c99e 100644 --- a/engine/src/flutter/docs/contributing/Setting-up-the-Engine-development-environment.md +++ b/engine/src/flutter/docs/contributing/Setting-up-the-Engine-development-environment.md @@ -82,7 +82,7 @@ gclient sync ### Xcode [Objective-C++] -On Mac, you can simply use Xcode (e.g., `open out/host_debug_unopt/products.xcodeproj`). +On Mac, you can simply use Xcode (e.g., `open out/host_debug_unopt/flutter_engine.xcodeproj`). ### VSCode with C/C++ Intellisense [C/C++] diff --git a/engine/src/flutter/engine.code-workspace b/engine/src/flutter/engine.code-workspace index 544677d98bfed..0d8f5d22f0680 100644 --- a/engine/src/flutter/engine.code-workspace +++ b/engine/src/flutter/engine.code-workspace @@ -425,6 +425,37 @@ "ios_debug_unopt" ] }, + { + "type": "shell", + "command": "./flutter/bin/et", + "options": { + "cwd": "${workspaceFolder}/.." + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "shared", + "clear": true + }, + "group": { + "kind": "build" + }, + "label": "ios_debug_sim_unopt_arm64", + "args": [ + "build", + "-c", + "host_debug_unopt_arm64", + "&&", + "./flutter/bin/et", + "build", + "-c", + "ios_debug_sim_unopt_arm64" + ] + }, { "type": "shell", "command": "./flutter/bin/et", diff --git a/engine/src/flutter/fml/BUILD.gn b/engine/src/flutter/fml/BUILD.gn index 1ebbdcfb136b4..6069cd53a5a86 100644 --- a/engine/src/flutter/fml/BUILD.gn +++ b/engine/src/flutter/fml/BUILD.gn @@ -189,6 +189,10 @@ source_set("fml") { ] } + if (is_qnx) { + sources += [ "platform/qnx/paths_qnx.cc" ] + } + if (is_fuchsia) { sources += [ "platform/fuchsia/log_interest_listener.cc", diff --git a/engine/src/flutter/fml/platform/qnx/paths_qnx.cc b/engine/src/flutter/fml/platform/qnx/paths_qnx.cc new file mode 100644 index 0000000000000..c3c0e61287a11 --- /dev/null +++ b/engine/src/flutter/fml/platform/qnx/paths_qnx.cc @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter 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/fml/paths.h" + +namespace fml { +namespace paths { + +std::pair GetExecutablePath() { + // Unsupported on this platform. + return {false, ""}; +} + +fml::UniqueFD GetCachesDirectory() { + // Unsupported on this platform. + return {}; +} + +} // namespace paths +} // namespace fml diff --git a/engine/src/flutter/impeller/core/vertex_buffer.h b/engine/src/flutter/impeller/core/vertex_buffer.h index bb4927eab602a..b6c37eb1324a7 100644 --- a/engine/src/flutter/impeller/core/vertex_buffer.h +++ b/engine/src/flutter/impeller/core/vertex_buffer.h @@ -30,7 +30,7 @@ struct VertexBuffer { /// IndexType index_type = IndexType::kUnknown; - constexpr explicit operator bool() const { + explicit inline operator bool() const { return static_cast(vertex_buffer) && (index_type == IndexType::kNone || static_cast(index_buffer)); } diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc index fefe068f54b33..ad77934c7e337 100644 --- a/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc +++ b/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc @@ -759,6 +759,213 @@ TEST_P(AiksTest, FilledEllipsesRenderCorrectly) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +namespace { +struct ArcFarmOptions { + bool use_center; + bool full_circles; + Scalar vertical_scale = 1.0f; +}; + +void RenderArcFarm(DisplayListBuilder& builder, + const DlPaint& paint, + const ArcFarmOptions& opts) { + builder.Save(); + builder.Translate(50, 50); + const Rect arc_bounds = Rect::MakeLTRB(0, 0, 42, 42 * opts.vertical_scale); + for (int start = 0; start <= 360; start += 30) { + builder.Save(); + for (int sweep = 30; sweep <= 360; sweep += 30) { + builder.DrawArc(arc_bounds, start, opts.full_circles ? 360 : sweep, + opts.use_center, paint); + builder.Translate(50, 0); + } + builder.Restore(); + builder.Translate(0, 50); + } + builder.Restore(); +} +} // namespace + +TEST_P(AiksTest, FilledArcsRenderCorrectly) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, FilledArcsRenderCorrectlyWithCenter) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = true, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectly) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + .vertical_scale = 0.8f, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectlyWithCenter) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = true, + .full_circles = false, + .vertical_scale = 0.8f, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithButtEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kSquare); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(8.0f); + paint.setStrokeCap(DlStrokeCap::kSquare); + paint.setColor(DlColor::kRed()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsCoverFullArcWithButtEnds) { + // This test compares the rendering of a full circle arc against a partial + // arc by drawing a one over the other in high contrast. If the partial + // arc misses any pixels that were drawn by the full arc, there will be + // some "pixel dirt" around the missing "erased" parts of the arcs. This + // case arises while rendering a CircularProgressIndicator with a background + // color where we want the rendering of the background full arc to hit the + // same pixels around the edges as the partial arc that covers it. + // + // In this case we draw a full blue circle and then draw a partial arc + // over it in the background color (white). + + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + // First draw full circles in blue to establish the pixels to be erased + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = true, + }); + + paint.setColor(DlColor::kWhite()); + + // Then draw partial arcs in white over the circles to "erase" them + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) { DisplayListBuilder builder; builder.Scale(GetContentScale().x, GetContentScale().y); diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 084db12a81084..8f88a5154478c 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -36,6 +36,7 @@ #include "impeller/entity/contents/text_shadow_cache.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" +#include "impeller/entity/geometry/arc_geometry.h" #include "impeller/entity/geometry/circle_geometry.h" #include "impeller/entity/geometry/cover_geometry.h" #include "impeller/entity/geometry/ellipse_geometry.h" @@ -349,9 +350,7 @@ void Canvas::DrawPaint(const Paint& paint) { // Optimization: if the texture has a color filter that is a simple // porter-duff blend or matrix filter, then instead of performing a save layer // we should swap out the shader for the porter duff blend shader and avoid a -// saveLayer. This can only be done for imageRects without a strict source -// rect, as the porter duff shader does not support this feature. This -// optimization is important for Flame. +// saveLayer. This optimization is important for Flame. bool Canvas::AttemptColorFilterOptimization( const std::shared_ptr& image, Rect source, @@ -359,11 +358,10 @@ bool Canvas::AttemptColorFilterOptimization( const Paint& paint, const SamplerDescriptor& sampler, SourceRectConstraint src_rect_constraint) { - if (src_rect_constraint == SourceRectConstraint::kStrict || // - !paint.color_filter || // - paint.image_filter != nullptr || // - paint.invert_colors || // - paint.mask_blur_descriptor.has_value() || // + if (!paint.color_filter || // + paint.image_filter != nullptr || // + paint.invert_colors || // + paint.mask_blur_descriptor.has_value() || // !IsPipelineBlendOrMatrixFilter(paint.color_filter)) { return false; } @@ -377,7 +375,9 @@ bool Canvas::AttemptColorFilterOptimization( /*destination=*/dest, /*color=*/skia_conversions::ToColor(blend_filter->color()), /*blend_mode=*/blend_filter->mode(), - /*desc=*/sampler); + /*desc=*/sampler, + /*use_strict_src_rect=*/src_rect_constraint == + SourceRectConstraint::kStrict); auto atlas_contents = std::make_shared(); atlas_contents->SetGeometry(&geometry); @@ -390,6 +390,12 @@ bool Canvas::AttemptColorFilterOptimization( AddRenderEntityToCurrentPass(entity); } else { + // src_rect_constraint is only supported in the porter-duff mode + // for now. + if (src_rect_constraint == SourceRectConstraint::kStrict) { + return false; + } + const flutter::DlMatrixColorFilter* matrix_filter = paint.color_filter->asMatrix(); @@ -399,7 +405,9 @@ bool Canvas::AttemptColorFilterOptimization( /*destination=*/dest, /*color=*/Color::Khaki(), // ignored /*blend_mode=*/BlendMode::kSrcOver, // ignored - /*desc=*/sampler); + /*desc=*/sampler, + /*use_strict_src_rect=*/src_rect_constraint == + SourceRectConstraint::kStrict); auto atlas_contents = std::make_shared(); atlas_contents->SetGeometry(&geometry); @@ -643,43 +651,63 @@ void Canvas::DrawOval(const Rect& rect, const Paint& paint) { } void Canvas::DrawArc(const Rect& oval_bounds, - Scalar start_degrees, - Scalar sweep_degrees, + Degrees start, + Degrees sweep, bool use_center, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - if (paint.style == Paint::Style::kStroke && - paint.stroke.width > oval_bounds.GetSize().MaxDimension()) { + if (paint.style == Paint::Style::kFill) { + ArcGeometry geom(oval_bounds, start, sweep, use_center); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + return; + } + + if (paint.stroke.width > oval_bounds.GetSize().MaxDimension()) { // This is a special case for rendering arcs whose stroke width is so large // you are effectively drawing a sector of a circle. // https://github.com/flutter/flutter/issues/158567 Rect expanded_rect = oval_bounds.Expand(Size(paint.stroke.width * 0.5f)); - flutter::DlPathBuilder builder; - builder.AddArc(expanded_rect, Degrees(start_degrees), - Degrees(sweep_degrees), /*use_center=*/true); - - Paint fill_paint = paint; - fill_paint.style = Paint::Style::kFill; - - ArcFillPathGeometry geom(builder.TakePath(), expanded_rect); + ArcGeometry geom(expanded_rect, start, sweep, /*include_center=*/true); AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); - } else { - flutter::DlPathBuilder builder; - builder.AddArc(oval_bounds, Degrees(start_degrees), Degrees(sweep_degrees), - use_center); + return; + } - if (paint.style == Paint::Style::kFill) { - ArcFillPathGeometry geom(builder.TakePath(), oval_bounds); - AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); - } else { - ArcStrokePathGeometry geom(builder.TakePath(), oval_bounds, paint.stroke); + // Use_center incurs lots of extra work for stroking an arc, including: + // - It introduces segments to/from the center point (not too hard). + // - It introduces joins on those segments (a bit more complicated). + // - Even if the sweep is >=360 degrees, we still draw the segment to + // the center and it basically looks like a pie cut into the complete + // boundary circle, as if the slice were cut, but not extracted + // (hard to express as a continuous kTriangleStrip). + if (!use_center) { + if (std::abs(sweep.degrees) >= 360.0f) { + return DrawOval(oval_bounds, paint); + } + + // Our fast stroking code only works for circular bounds as it assumes + // that the inner and outer radii can be scaled along each angular step + // of the arc - which is not true for elliptical arcs where the inner + // and outer samples are perpendicular to the traveling direction of the + // elliptical curve which may not line up with the center of the bounds. + // + // TODO(flar): It also only supports Butt and Square caps for now. + // See https://github.com/flutter/flutter/issues/169400 + if (oval_bounds.IsSquare() && paint.stroke.cap != Cap::kRound) { + ArcGeometry geom(oval_bounds, start, sweep, paint.stroke); AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + return; } } + + flutter::DlPathBuilder builder; + builder.AddArc(oval_bounds, start, sweep, use_center); + + ArcStrokePathGeometry geom(builder.TakePath(), oval_bounds, paint.stroke); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawRoundRect(const RoundRect& round_rect, const Paint& paint) { @@ -730,29 +758,26 @@ void Canvas::DrawDiffRoundRect(const RoundRect& outer, } } -void Canvas::DrawRoundSuperellipse(const RoundSuperellipse& rse, +void Canvas::DrawRoundSuperellipse(const RoundSuperellipse& round_superellipse, const Paint& paint) { - auto& rect = rse.GetBounds(); - auto& radii = rse.GetRadii(); + auto& rect = round_superellipse.GetBounds(); + auto& radii = round_superellipse.GetRadii(); if (radii.AreAllCornersSame() && AttemptDrawBlurredRSuperellipse(rect, radii.top_left, paint)) { return; } - if (paint.style == Paint::Style::kFill) { - Entity entity; - entity.SetTransform(GetCurrentTransform()); - entity.SetBlendMode(paint.blend_mode); + Entity entity; + entity.SetTransform(GetCurrentTransform()); + entity.SetBlendMode(paint.blend_mode); + if (paint.style == Paint::Style::kFill) { RoundSuperellipseGeometry geom(rect, radii); AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); - return; + } else { + StrokeRoundSuperellipseGeometry geom(round_superellipse, paint.stroke); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } - - auto path = flutter::DlPathBuilder{} // - .AddRoundSuperellipse(rse) - .TakePath(); - DrawPath(flutter::DlPath(path), paint); } void Canvas::DrawCircle(const Point& center, diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index 0c4ac8af3c82a..323a5650d3ccd 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -204,8 +204,8 @@ class Canvas { void DrawOval(const Rect& rect, const Paint& paint); void DrawArc(const Rect& oval_bounds, - Scalar start_degrees, - Scalar sweep_degrees, + Degrees start, + Degrees sweep, bool use_center, const Paint& paint); diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 606c39e595b23..fcaa4bd5e1f00 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -679,8 +679,8 @@ void DlDispatcherBase::drawArc(const DlRect& oval_bounds, bool use_center) { AUTO_DEPTH_WATCHER(1u); - GetCanvas().DrawArc(oval_bounds, start_degrees, sweep_degrees, use_center, - paint_); + GetCanvas().DrawArc(oval_bounds, Degrees(start_degrees), + Degrees(sweep_degrees), use_center, paint_); } // |flutter::DlOpReceiver| diff --git a/engine/src/flutter/impeller/docs/faq.md b/engine/src/flutter/impeller/docs/faq.md index 9ff20fbd43822..4cf4dbda80c8d 100644 --- a/engine/src/flutter/impeller/docs/faq.md +++ b/engine/src/flutter/impeller/docs/faq.md @@ -290,6 +290,54 @@ at startup time. But it still aims to support Skia’s general 2D API and has th same spec. requirements. The design decisions made to support those requirements make offline shader compilation impossible. -As of August 2024, Flutter has no plans to use Graphite. However, we, the +As of May 2025, Flutter has no plans to use Graphite. However, we, the Flutter team, are in constant communication with the Skia team and freely share insights and ideas across Impeller and Graphite. + +### How does WebGPU/Dawn fit into the rendering landscape in Flutter? + +To access graphics/compute accelerators on the device, you need to go through a client API like Vulkan, OpenGL, Metal, DirectX, etc… Rendering engines like Impeller, Skia, ThreeJS (we’ll call them middleware) all have the same concern. The client APIs are extremely low-level, not fully platform/device agnostic, and difficult to target/maintain individually. Depending on the application's needs, you can get away with targeting just one client API. Sometimes, client APIs can be layered on top of another. For instance, running WebGL in the browser likely uses Metal under the hood (via Angle) when the browser is running on macOS. + +```mermaid +flowchart TD + GraphicsHardware["Graphics Hardware"] + Impeller --> OpenGL + Skia --> OpenGL + Others --> OpenGL + Impeller --> Metal + Skia --> Metal + Others --> Metal + Impeller --> Vulkan + Skia --> Vulkan + Others --> Vulkan + OpenGL --> GraphicsHardware + Metal --> GraphicsHardware + Vulkan --> GraphicsHardware + +``` + +WebGPU, or Dawn/wgpu.rs in JS garb, purports to be a sensible and portable abstraction layer over the [client APIs](https://dawn.googlesource.com/dawn/+/HEAD/docs/support.md). For middleware, that presents an interesting value proposition. Instead of doing mostly the same thing multiple times, you just target one API and let the WebGPU library take care of the rest. + +```mermaid +flowchart TD + GraphicsHardware["Graphics Hardware"] + Impeller --> Dawn + Skia --> Dawn + Others --> Dawn + OpenGL --> GraphicsHardware + Metal --> GraphicsHardware + Vulkan --> GraphicsHardware + Dawn --> OpenGL + Dawn --> Metal + Dawn --> Vulkan +``` + +However, for middleware like Impeller, there are a few practical considerations that make Dawn unsuitable for use today. For one, the binary size of the library is larger than the entire Flutter Engine. Flutter users are incredibly sensitive to binary size and more than doubling the size of the engine is a tough pill to swallow. In comparison, Impeller adds only about 100kb of binary size to the Flutter Engine today. Next, the WebGPU abstraction locks us out of features available directly in client API that Impeller freely exploits for performance (framebuffer-fetch, fixed-rate compression for intermediate render targets, etc…). Impeller would either have to wait for official support for it in Dawn or poke holes in the API which increases our support surface. But, we are not averse to having a WebGPU backend for Flutter. In fact, we’ve already done experiments where our compiler can target [WGSL](https://github.com/chinmaygarde/wgsl_sandbox) and are ready to support WebGPU when/where it makes sense. But, right now, we are in a situation where a WebGPU backend will be **in-addition-to** the other backends and not **instead-of**. This defeats the primary value proposition of WebGPU/Dawn which is not having to maintain multiple backends in the first place. + +As of May 2025, Impeller has no plans to add a WebGPU/Dawn backend. We will re-evaluate this decision if/when one or both of the following conditions hold: +* WebGPU is the only available client API on the platform capable of servicing Flutters needs. Hypothetically, this could be a path Impeller takes on the web instead of using WebGL 2. Though, we must admit it's a tough decision today. +* WebGPU is the preferred client API on a platform and is available on that platform already (negating Impellers concerns about binary size). Flutter targets no such platforms today. + +We do get queries about WebGPU from the perspective of application developers, **not** middleware like Impeller. Flutter does have the ability to poke a hole in the middleware for applications to support specific rendering use-cases. For instance, plugins use it to render into a texture using client APIs directly. But as soon as you attempt to do your own rendering, you hit a massive usability cliff where you need to support all client APIs portably. WebGPU starts looking like just the thing you need. FWIW, application developers can write bindings to WebGPU using the plugin model with FFI and use those bindings to write a renderer that renders to a texture that gets composited in a Flutter application. But it's going to be very hard. And developers will likely lose the benefits of stateful hot-reload and all the other developer affordances that are part of Flutters value proposition unless significant investments are made in the developer experience. The author's role as a middleware developer with the constraints listed above disincentives them from making such an investment. So this is a call to the community for a high-quality WebGPU package. + +Admittedly, a gap in Flutters rendering support is that there is no way to create a delightful 3D renderer in Flutter without also first escaping from Flutter. That an escape hatch (via FFI/plugins) exists is perhaps missing the point. Talking about how someone could use WebGPU once they use that escape hatch even more so. A potentially exciting proposal is [Flutter GPU](https://docs.google.com/document/d/1Sh1BAC5c_kkuMVreo7ymBzPoMzb7lamZRPsI7GBXv5M/edit?resourcekey=0-5w8u2V-LS41tCHeoE8bDTQ&tab=t.0). It would expose a really low-level (but still Dart) interface to accelerators in a portable manner. Package authors will then be able to write renderers in Dart (similar to ThreeJS) that integrate well with existing Canvas APIs (no platform views, no texture composition, etc…). The progress is compelling but slow given current resource constraints on the team. diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn index 2264682efd73b..3f0e9aeabe489 100644 --- a/engine/src/flutter/impeller/entity/BUILD.gn +++ b/engine/src/flutter/impeller/entity/BUILD.gn @@ -200,6 +200,8 @@ impeller_component("entity") { "entity_pass_clip_stack.h", "entity_pass_target.cc", "entity_pass_target.h", + "geometry/arc_geometry.cc", + "geometry/arc_geometry.h", "geometry/circle_geometry.cc", "geometry/circle_geometry.h", "geometry/cover_geometry.cc", diff --git a/engine/src/flutter/impeller/entity/contents/atlas_contents.cc b/engine/src/flutter/impeller/entity/contents/atlas_contents.cc index 6bd795a07afd5..581350ba9508b 100644 --- a/engine/src/flutter/impeller/entity/contents/atlas_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/atlas_contents.cc @@ -23,13 +23,15 @@ DrawImageRectAtlasGeometry::DrawImageRectAtlasGeometry( const Rect& destination, const Color& color, BlendMode blend_mode, - const SamplerDescriptor& desc) + const SamplerDescriptor& desc, + bool use_strict_src_rect) : texture_(std::move(texture)), source_(source), destination_(destination), color_(color), blend_mode_(blend_mode), - desc_(desc) {} + desc_(desc), + use_strict_src_rect_(use_strict_src_rect) {} DrawImageRectAtlasGeometry::~DrawImageRectAtlasGeometry() = default; @@ -123,6 +125,13 @@ bool DrawImageRectAtlasGeometry::ShouldInvertBlendMode() const { return false; } +std::optional DrawImageRectAtlasGeometry::GetStrictSrcRect() const { + if (use_strict_src_rect_) { + return source_; + } + return std::nullopt; +} + //// AtlasContents::AtlasContents() = default; @@ -215,12 +224,18 @@ bool AtlasContents::Render(const ContentContext& renderer, frame_info.texture_sampler_y_coord_scale = geometry_->GetAtlas()->GetYCoordScale(); - frag_info.output_alpha = alpha_; - frag_info.input_alpha = 1.0; - - // These values are ignored on platforms that natively support decal. - frag_info.tmx = static_cast(Entity::TileMode::kDecal); - frag_info.tmy = static_cast(Entity::TileMode::kDecal); + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(1.0, alpha_, static_cast(Entity::TileMode::kDecal), + static_cast(Entity::TileMode::kDecal)); + if (auto rect = geometry_->GetStrictSrcRect(); rect.has_value()) { + Rect src_rect = rect.value(); + frag_info.source_rect = + Vector4(src_rect.GetX(), src_rect.GetY(), src_rect.GetBottom(), + src_rect.GetRight()); + frag_info.use_strict_source_rect = 1.0; + } else { + frag_info.use_strict_source_rect = 0.0; + } FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); diff --git a/engine/src/flutter/impeller/entity/contents/atlas_contents.h b/engine/src/flutter/impeller/entity/contents/atlas_contents.h index 978ee0796d1aa..c56c46bca4bb0 100644 --- a/engine/src/flutter/impeller/entity/contents/atlas_contents.h +++ b/engine/src/flutter/impeller/entity/contents/atlas_contents.h @@ -39,6 +39,12 @@ class AtlasGeometry { virtual BlendMode GetBlendMode() const = 0; virtual bool ShouldInvertBlendMode() const { return true; } + + /// @brief The source rect of the draw if a strict source rect should + /// be applied, or nullopt. + /// + /// See also `Canvas::AttemptColorFilterOptimization` + virtual std::optional GetStrictSrcRect() const { return std::nullopt; } }; /// @brief An atlas geometry that adapts for drawImageRect. @@ -49,7 +55,8 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { const Rect& destination, const Color& color, BlendMode blend_mode, - const SamplerDescriptor& desc); + const SamplerDescriptor& desc, + bool use_strict_src_rect = false); ~DrawImageRectAtlasGeometry(); @@ -71,6 +78,8 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { bool ShouldInvertBlendMode() const override; + std::optional GetStrictSrcRect() const override; + private: const std::shared_ptr texture_; const Rect source_; @@ -78,6 +87,7 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { const Color color_; const BlendMode blend_mode_; const SamplerDescriptor desc_; + const bool use_strict_src_rect_; }; class AtlasContents final : public Contents { diff --git a/engine/src/flutter/impeller/entity/contents/clip_contents.cc b/engine/src/flutter/impeller/entity/contents/clip_contents.cc index c778bec336c7b..b01b0efcf582c 100644 --- a/engine/src/flutter/impeller/entity/contents/clip_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/clip_contents.cc @@ -45,7 +45,7 @@ void ClipContents::SetClipOperation(Entity::ClipOperation clip_op) { ClipCoverage ClipContents::GetClipCoverage( const std::optional& current_clip_coverage) const { if (!current_clip_coverage.has_value()) { - return {.coverage = std::nullopt}; + return ClipCoverage{.coverage = std::nullopt}; } switch (clip_op_) { case Entity::ClipOperation::kDifference: @@ -57,7 +57,7 @@ ClipCoverage ClipContents::GetClipCoverage( }; case Entity::ClipOperation::kIntersect: if (coverage_rect_.IsEmpty() || !current_clip_coverage.has_value()) { - return {.coverage = std::nullopt}; + return ClipCoverage{.coverage = std::nullopt}; } return { .is_difference_or_non_square = !is_axis_aligned_rect_, // diff --git a/engine/src/flutter/impeller/entity/contents/content_context.h b/engine/src/flutter/impeller/entity/contents/content_context.h index 28be0eed419d2..73a39a453587a 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.h +++ b/engine/src/flutter/impeller/entity/contents/content_context.h @@ -322,8 +322,8 @@ class ContentContext { }; struct Equal { - constexpr bool operator()(const RuntimeEffectPipelineKey& lhs, - const RuntimeEffectPipelineKey& rhs) const { + inline bool operator()(const RuntimeEffectPipelineKey& lhs, + const RuntimeEffectPipelineKey& rhs) const { return lhs.unique_entrypoint_name == rhs.unique_entrypoint_name && lhs.options.ToKey() == rhs.options.ToKey(); } diff --git a/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc index f9196a68a679e..3d0fb91551251 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc @@ -471,11 +471,12 @@ std::optional BlendFilterContents::CreateForegroundPorterDuffBlend( frame_info.texture_sampler_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - frag_info.input_alpha = - absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes - ? dst_snapshot->opacity * alpha.value_or(1.0) - : 1.0; - frag_info.output_alpha = 1.0; + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes + ? dst_snapshot->opacity * alpha.value_or(1.0) + : 1.0, + 1, 0, 0); + frag_info.use_strict_source_rect = 0.0; FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); diff --git a/engine/src/flutter/impeller/entity/contents/vertices_contents.cc b/engine/src/flutter/impeller/entity/contents/vertices_contents.cc index 1e0d06d631460..13e98ce0f6b0c 100644 --- a/engine/src/flutter/impeller/entity/contents/vertices_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/vertices_contents.cc @@ -164,12 +164,10 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer, frame_info.texture_sampler_y_coord_scale = texture->GetYCoordScale(); frame_info.mvp = geometry_result.transform; - frag_info.output_alpha = alpha_; - frag_info.input_alpha = 1.0; - - // These values are ignored if the platform supports native decal mode. - frag_info.tmx = static_cast(tile_mode_x_); - frag_info.tmy = static_cast(tile_mode_y_); + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(1, alpha_, static_cast(tile_mode_x_), + static_cast(tile_mode_y_)); + frag_info.use_strict_source_rect = 0.0; auto& host_buffer = renderer.GetTransientsBuffer(); FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); diff --git a/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc b/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc new file mode 100644 index 0000000000000..ba8d33e0755d4 --- /dev/null +++ b/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc @@ -0,0 +1,145 @@ +// Copyright 2013 The Flutter 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/impeller/entity/geometry/arc_geometry.h" + +#include "flutter/impeller/entity/geometry/line_geometry.h" + +namespace impeller { + +ArcGeometry::ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center) + : oval_bounds_(oval_bounds), + start_(start), + sweep_(sweep), + include_center_(include_center), + stroke_width_(-1.0f), + cap_(Cap::kButt) {} + +ArcGeometry::ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke) + : oval_bounds_(oval_bounds), + start_(start), + sweep_(sweep), + include_center_(false), + stroke_width_(stroke.width), + cap_(stroke.cap) { + FML_DCHECK(oval_bounds_.IsSquare()); +} + +ArcGeometry::~ArcGeometry() = default; + +// |Geometry| +Scalar ArcGeometry::ComputeAlphaCoverage(const Matrix& transform) const { + if (stroke_width_ < 0) { + return 1; + } + return Geometry::ComputeStrokeAlphaCoverage(transform, stroke_width_); +} + +GeometryResult ArcGeometry::GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + auto& transform = entity.GetTransform(); + + if (stroke_width_ < 0) { + auto generator = renderer.GetTessellator().FilledArc( + transform, oval_bounds_, start_, sweep_, include_center_, + renderer.GetDeviceCapabilities().SupportsTriangleFan()); + + return ComputePositionGeometry(renderer, generator, entity, pass); + } else { + FML_DCHECK(oval_bounds_.IsSquare()); + Scalar half_width = + LineGeometry::ComputePixelHalfWidth(transform, stroke_width_); + + auto generator = renderer.GetTessellator().StrokedArc( + transform, oval_bounds_, start_, sweep_, cap_, half_width); + + return ComputePositionGeometry(renderer, generator, entity, pass); + } +} + +std::optional ArcGeometry::GetCoverage(const Matrix& transform) const { + Scalar padding = // + stroke_width_ < 0 + ? 0.0 + : LineGeometry::ComputePixelHalfWidth(transform, stroke_width_); + + if (sweep_.degrees <= -360 || sweep_.degrees >= 360) { + return oval_bounds_.Expand(padding).TransformAndClipBounds(transform); + } + + if (cap_ == Cap::kSquare) { + padding = padding * kSqrt2; + } + + Degrees start_angle, end_angle; + if (sweep_.degrees < 0) { + start_angle = (start_ + sweep_).GetPositive(); + end_angle = start_angle - sweep_; + } else { + start_angle = start_.GetPositive(); + end_angle = start_angle + sweep_; + } + FML_DCHECK(start_angle.degrees >= 0 && start_angle.degrees < 360); + FML_DCHECK(end_angle > start_angle && end_angle.degrees < 720); + + // 1. start vector + // 2. end vector + // 3. optional center + // 4-7. optional quadrant extrema + Point extrema[7]; + int count = 0; + + extrema[count++] = Matrix::CosSin(start_angle); + extrema[count++] = Matrix::CosSin(end_angle); + + if (include_center_) { + // We don't handle strokes with include_center so the stroking + // parameters should be the default. + FML_DCHECK(stroke_width_ < 0 && cap_ == Cap::kButt && padding == 0.0f); + extrema[count++] = {0, 0}; + } + + // cur_axis will be pre-incremented before recording the following axis + int cur_axis = std::floor(start_angle.degrees / 90.0f); + // end_axis is a non-inclusive end of the range + int end_axis = std::ceil(end_angle.degrees / 90.0f); + while (++cur_axis < end_axis) { + extrema[count++] = kQuadrantAxes[cur_axis & 3]; + } + + FML_DCHECK(count <= 7); + + Point center = oval_bounds_.GetCenter(); + Size radii = oval_bounds_.GetSize() * 0.5f; + + for (int i = 0; i < count; i++) { + extrema[i] = center + extrema[i] * radii; + } + auto opt_rect = Rect::MakePointBounds(extrema, extrema + count); + if (opt_rect.has_value()) { + // Pretty much guaranteed because count >= 2... + opt_rect = opt_rect // + .value() + .Expand(padding) + .TransformAndClipBounds(transform); + } + return opt_rect; +} + +bool ArcGeometry::CoversArea(const Matrix& transform, const Rect& rect) const { + return false; +} + +bool ArcGeometry::IsAxisAlignedRect() const { + return false; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/arc_geometry.h b/engine/src/flutter/impeller/entity/geometry/arc_geometry.h new file mode 100644 index 0000000000000..b06a7b6a5f1d0 --- /dev/null +++ b/engine/src/flutter/impeller/entity/geometry/arc_geometry.h @@ -0,0 +1,62 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ +#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ + +#include "impeller/entity/geometry/geometry.h" + +#include "impeller/geometry/stroke_parameters.h" + +namespace impeller { + +// Geometry class that can generate vertices (with or without texture +// coordinates) for either filled or stroked circles +class ArcGeometry final : public Geometry { + public: + explicit ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center); + + explicit ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke); + + ~ArcGeometry() override; + + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + + // |Geometry| + bool IsAxisAlignedRect() const override; + + // |Geometry| + Scalar ComputeAlphaCoverage(const Matrix& transform) const override; + + private: + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + // |Geometry| + std::optional GetCoverage(const Matrix& transform) const override; + + Rect oval_bounds_; + Degrees start_; + Degrees sweep_; + bool include_center_; + Scalar stroke_width_; + Cap cap_; + + ArcGeometry(const ArcGeometry&) = delete; + + ArcGeometry& operator=(const ArcGeometry&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ diff --git a/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc b/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc index c7f6640c4e83a..8b1a467134041 100644 --- a/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc @@ -57,17 +57,10 @@ GeometryResult CircleGeometry::GetPositionBuffer(const ContentContext& renderer, std::optional CircleGeometry::GetCoverage(const Matrix& transform) const { Scalar half_width = stroke_width_ < 0 ? 0.0 : stroke_width_ * 0.5f; Scalar outer_radius = radius_ + half_width; - Point corners[4]{ - {center_.x, center_.y - outer_radius}, - {center_.x + outer_radius, center_.y}, - {center_.x, center_.y + outer_radius}, - {center_.x - outer_radius, center_.y}, - }; - - for (int i = 0; i < 4; i++) { - corners[i] = transform * corners[i]; - } - return Rect::MakePointBounds(std::begin(corners), std::end(corners)); + return Rect::MakeLTRB(-outer_radius, -outer_radius, // + +outer_radius, +outer_radius) + .Shift(center_) + .TransformAndClipBounds(transform); } bool CircleGeometry::CoversArea(const Matrix& transform, diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.cc b/engine/src/flutter/impeller/entity/geometry/geometry.cc index 2e59d0cedf7b6..e8a2450501982 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry.cc @@ -9,6 +9,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/pipelines.h" +#include "impeller/entity/geometry/arc_geometry.h" #include "impeller/entity/geometry/circle_geometry.h" #include "impeller/entity/geometry/cover_geometry.h" #include "impeller/entity/geometry/ellipse_geometry.h" @@ -104,6 +105,22 @@ std::unique_ptr Geometry::MakeStrokedCircle(const Point& center, return std::make_unique(center, radius, stroke_width); } +std::unique_ptr Geometry::MakeFilledArc(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center) { + return std::make_unique(oval_bounds, start, sweep, + include_center); +} + +std::unique_ptr Geometry::MakeStrokedArc( + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke) { + return std::make_unique(oval_bounds, start, sweep, stroke); +} + std::unique_ptr Geometry::MakeRoundRect(const Rect& rect, const Size& radii) { return std::make_unique(rect, radii); diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.h b/engine/src/flutter/impeller/entity/geometry/geometry.h index 107ed9bea97a0..44069f8a7459a 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/geometry.h @@ -76,6 +76,17 @@ class Geometry { Scalar radius, Scalar stroke_width); + static std::unique_ptr MakeFilledArc(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center); + + static std::unique_ptr MakeStrokedArc( + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke); + static std::unique_ptr MakeRoundRect(const Rect& rect, const Size& radii); diff --git a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc index 2bc2ea470db7e..926673aa3b9d3 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc @@ -97,6 +97,373 @@ TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) { ASSERT_FALSE(geometry->CoversArea({}, Rect())); } +TEST(EntityGeometryTest, FillArcGeometryCoverage) { + Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200); + Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-oval_bounds.GetCenter()); + + { // Sweeps <=-360 or >=360 + for (int start = -720; start <= 720; start += 10) { + for (int sweep = 360; sweep <= 720; sweep += 30) { + std::string label = + "start: " + std::to_string(start) + " + " + std::to_string(sweep); + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(sweep), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << sweep; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-sweep), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << -sweep; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-sweep), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << -sweep << ", with center"; + } + } + } + { // Sweep from late in one quadrant to earlier in same quadrant + for (int start = 60; start < 360; start += 90) { + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(330), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(330), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep from early in one quadrant backwards to later in same quadrant + for (int start = 30; start < 360; start += 90) { + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-330), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-330), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep past each quadrant axis individually, no center + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start - 45), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2, // + 200, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 45), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2, // + 200); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 135), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(100, // + 150 - 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 225), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 100, // + 150 + 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // Sweep past each quadrant axis individually, including the center + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start - 45), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150, // + 150 - 50 * kSqrt2Over2, // + 200, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 45), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 150, // + 150 + 50 * kSqrt2Over2, // + 200); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 135), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(100, // + 150 - 50 * kSqrt2Over2, // + 150, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 225), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 100, // + 150 + 50 * kSqrt2Over2, // + 150); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // 45 degree tilted full circle + auto geometry = + Geometry::MakeFilledArc(oval_bounds, Degrees(0), Degrees(360), false); + ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(oval_bounds)); + } + { // 45 degree tilted mostly full circle + auto geometry = + Geometry::MakeFilledArc(oval_bounds, Degrees(3), Degrees(359), false); + ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(oval_bounds)); + } +} + +TEST(EntityGeometryTest, StrokeArcGeometryCoverage) { + Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200); + Rect expanded_bounds = Rect::MakeLTRB(95, 95, 205, 205); + Rect squared_bounds = Rect::MakeLTRB(100 - 5 * kSqrt2, 100 - 5 * kSqrt2, + 200 + 5 * kSqrt2, 200 + 5 * kSqrt2); + Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-oval_bounds.GetCenter()); + + StrokeParameters butt_params = { + .width = 10.0f, + .cap = Cap::kButt, + }; + StrokeParameters square_params = { + .width = 10.0f, + .cap = Cap::kSquare, + }; + + { // Sweeps <=-360 or >=360 + for (int start = -720; start <= 720; start += 10) { + for (int sweep = 360; sweep <= 720; sweep += 30) { + std::string label = + "start: " + std::to_string(start) + " + " + std::to_string(sweep); + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(sweep), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << sweep; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-sweep), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << -sweep; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-sweep), square_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << -sweep << ", square caps"; + } + } + } + { // Sweep from late in one quadrant to earlier in same quadrant + for (int start = 60; start < 360; start += 90) { + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(330), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", butt caps"; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(330), square_params); + EXPECT_EQ(geometry->GetCoverage({}), squared_bounds) + << "start: " << start << ", square caps"; + } + } + { // Sweep from early in one quadrant backwards to later in same quadrant + for (int start = 30; start < 360; start += 90) { + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-330), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-330), square_params); + EXPECT_EQ(geometry->GetCoverage({}), squared_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep past each quadrant axis individually with butt caps + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start - 45), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - 5, // + 150 - 50 * kSqrt2Over2 - 5, // + 205, // + 150 + 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 45), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5, // + 150 + 50 * kSqrt2Over2 - 5, // + 150 + 50 * kSqrt2Over2 + 5, // + 205); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 135), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(95, // + 150 - 50 * kSqrt2Over2 - 5, // + 150 - 50 * kSqrt2Over2 + 5, // + 150 + 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 225), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5, // + 95, // + 150 + 50 * kSqrt2Over2 + 5, // + 150 - 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // Sweep past each quadrant axis individually with square caps + Scalar pad = 5 * kSqrt2; + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start - 45), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - pad, // + 150 - 50 * kSqrt2Over2 - pad, // + 200 + pad, // + 150 + 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 45), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad, // + 150 + 50 * kSqrt2Over2 - pad, // + 150 + 50 * kSqrt2Over2 + pad, // + 200 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 135), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(100 - pad, // + 150 - 50 * kSqrt2Over2 - pad, // + 150 - 50 * kSqrt2Over2 + pad, // + 150 + 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 225), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad, // + 100 - pad, // + 150 + 50 * kSqrt2Over2 + pad, // + 150 - 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // 45 degree tilted full circle, butt caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(0), Degrees(360), butt_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(expanded_bounds)); + } + { // 45 degree tilted full circle, square caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(0), Degrees(360), square_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(squared_bounds)); + } + { // 45 degree tilted mostly full circle, butt caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(3), Degrees(359), butt_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(expanded_bounds)); + } + { // 45 degree tilted mostly full circle, square caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(3), Degrees(359), square_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(squared_bounds)); + } +} + TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) { Rect bounds = Rect::MakeLTRB(100, 100, 200, 200); RoundRect round_rect = @@ -941,5 +1308,39 @@ TEST(EntityGeometryTest, TightCubic180DegreeJoins) { EXPECT_GT(points_round.size(), points_reference.size()); } +TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) { + Point center = Point(50, 50); + auto geometry = Geometry::MakeCircle(center, 50); + Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100); + ASSERT_EQ(geometry->GetCoverage({}).value_or(Rect()), circle_bounds); + + Matrix transform45 = Matrix::MakeTranslation(center) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-center); + + EXPECT_TRUE(geometry->GetCoverage(transform45).has_value()); + Rect bounds = geometry->GetCoverage(transform45).value_or(Rect()); + EXPECT_TRUE(bounds.Contains(circle_bounds)) + << "geometry bounds: " << bounds << std::endl + << " circle bounds: " << circle_bounds; +} + +TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) { + Point center = Point(50, 50); + auto geometry = Geometry::MakeStrokedCircle(center, 50, 10); + Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100).Expand(5); + ASSERT_EQ(geometry->GetCoverage({}).value_or(Rect()), circle_bounds); + + Matrix transform45 = Matrix::MakeTranslation(center) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-center); + + EXPECT_TRUE(geometry->GetCoverage(transform45).has_value()); + Rect bounds = geometry->GetCoverage(transform45).value_or(Rect()); + EXPECT_TRUE(bounds.Contains(circle_bounds)) + << "geometry bounds: " << bounds << std::endl + << " circle bounds: " << circle_bounds; +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h b/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h index 9b50302710543..6b4b612d67a85 100644 --- a/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/round_rect_geometry.h @@ -8,6 +8,7 @@ #include "impeller/entity/geometry/fill_path_geometry.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" +#include "impeller/geometry/round_rect.h" namespace impeller { diff --git a/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.cc b/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.cc index 4dee1949cef7e..5a6b72668f8d1 100644 --- a/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.cc @@ -462,4 +462,14 @@ bool RoundSuperellipseGeometry::IsAxisAlignedRect() const { return false; } +StrokeRoundSuperellipseGeometry::StrokeRoundSuperellipseGeometry( + const RoundSuperellipse& round_superellipse, + const StrokeParameters& parameters) + : StrokePathSourceGeometry(parameters), + round_superellipse_source_(round_superellipse) {} + +const PathSource& StrokeRoundSuperellipseGeometry::GetSource() const { + return round_superellipse_source_; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.h b/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.h index 9cb17474961ca..9020d03adbef8 100644 --- a/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/round_superellipse_geometry.h @@ -6,22 +6,27 @@ #define FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_ #include "impeller/entity/geometry/geometry.h" +#include "impeller/entity/geometry/stroke_path_geometry.h" +#include "impeller/geometry/round_superellipse.h" #include "impeller/geometry/rounding_radii.h" namespace impeller { - -/// Geometry class that can generate vertices for a rounded superellipse. +/// @brief A Geometry class that generates fillable vertices (with or without +/// texture coordinates) directly from a round superellipse object +/// regardless of radii uniformity. /// /// A rounded superellipse is a shape similar to a typical rounded rectangle -/// (`RoundRect`), but with smoother transitions between the straight sides and -/// the rounded corners. It resembles the `RoundedRectangle` shape in SwiftUI -/// with the `.continuous` corner style. Technically, it is created by replacing -/// the four corners of a superellipse (also known as a Lamé curve) with -/// circular arcs. +/// (`RoundSuperellipse`), but with smoother transitions between the straight +/// sides and the rounded corners. It resembles the `RoundedRectangle` shape in +/// SwiftUI with the `.continuous` corner style. Technically, it is created by +/// replacing the four corners of a superellipse (also known as a Lamé curve) +/// with circular arcs. /// /// The `bounds` defines the position and size of the shape. The `corner_radius` /// corresponds to SwiftUI's `cornerRadius` parameter, which is close to, but /// not exactly equals to, the radius of the corner circles. +/// +/// @see |StrokeRoundSuperellipseGeometry| class RoundSuperellipseGeometry final : public Geometry { public: RoundSuperellipseGeometry(const Rect& bounds, const RoundingRadii& radii); @@ -53,6 +58,27 @@ class RoundSuperellipseGeometry final : public Geometry { delete; }; +/// @brief A Geometry class that produces fillable vertices representing +/// the stroked outline of any |RoundSuperellipse| object regardless of +/// radii uniformity. +/// +/// This class uses the |StrokePathSourceGeometry| base class to do the work +/// by providing a |RoundSuperellipsePathSoure| iterator. +/// +/// @see |RoundSuperellipseGeometry| +class StrokeRoundSuperellipseGeometry final : public StrokePathSourceGeometry { + public: + StrokeRoundSuperellipseGeometry(const RoundSuperellipse& round_superellipse, + const StrokeParameters& parameters); + + protected: + // |StrokePathSourceGeometry| + const PathSource& GetSource() const override; + + private: + const RoundSuperellipsePathSource round_superellipse_source_; +}; + } // namespace impeller #endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_ROUND_SUPERELLIPSE_GEOMETRY_H_ diff --git a/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag b/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag index d7eb34caf5547..50fa645645c88 100644 --- a/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag +++ b/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag @@ -20,35 +20,46 @@ layout(constant_id = 5) const float dst_coeff_src_color = 1.0; uniform f16sampler2D texture_sampler_dst; uniform FragInfo { - float16_t input_alpha; - float16_t output_alpha; - float tmx; - float tmy; + // packed input, output alpha and x/y tilemodes. + vec4 input_alpha_output_alpha_tmx_tmy; + vec4 source_rect; + // When value is non-zero, uses texture coordinates clamped by `source_rect`. + float use_strict_source_rect; } frag_info; +float input_alpha = frag_info.input_alpha_output_alpha_tmx_tmy.x; +float output_alpha = frag_info.input_alpha_output_alpha_tmx_tmy.y; +float tile_mode_x = frag_info.input_alpha_output_alpha_tmx_tmy.z; +float tile_mode_y = frag_info.input_alpha_output_alpha_tmx_tmy.w; + in vec2 v_texture_coords; in f16vec4 v_color; out vec4 frag_color; -f16vec4 Sample(f16sampler2D texture_sampler, - vec2 texture_coords, - float tmx, - float tmy) { +f16vec4 Sample(f16sampler2D texture_sampler, vec2 texture_coords) { if (supports_decal > 0.0) { return texture(texture_sampler, texture_coords); } - return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tmx, tmy); + return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tile_mode_x, + tile_mode_y); } void main() { - f16vec4 dst = Sample(texture_sampler_dst, v_texture_coords, frag_info.tmx, - frag_info.tmy) * - frag_info.input_alpha; + vec2 texture_coords = + mix(v_texture_coords, + vec2(clamp(v_texture_coords.x, frag_info.source_rect.x, + frag_info.source_rect.z), + clamp(v_texture_coords.y, frag_info.source_rect.y, + frag_info.source_rect.w)), + frag_info.use_strict_source_rect); + + f16vec4 dst = + Sample(texture_sampler_dst, texture_coords) * float16_t(input_alpha); f16vec4 src = v_color; frag_color = f16vec4(src * (src_coeff + dst.a * src_coeff_dst_alpha) + dst * (dst_coeff + src.a * dst_coeff_src_alpha + src * dst_coeff_src_color)); - frag_color *= frag_info.output_alpha; + frag_color *= output_alpha; } diff --git a/engine/src/flutter/impeller/geometry/color.cc b/engine/src/flutter/impeller/geometry/color.cc index aa77cda7e6809..b7963b04b5b5e 100644 --- a/engine/src/flutter/impeller/geometry/color.cc +++ b/engine/src/flutter/impeller/geometry/color.cc @@ -136,7 +136,7 @@ static constexpr inline Color ApplyBlendedColor(Color dst, return src + dst * (1.0f - src.alpha); } -static constexpr inline Color DoColorBlend( +static inline Color DoColorBlend( Color dst, Color src, const std::function& blend_rgb_func) { @@ -144,7 +144,7 @@ static constexpr inline Color DoColorBlend( return ApplyBlendedColor(dst, src, blend_result).Unpremultiply(); } -static constexpr inline Color DoColorBlendComponents( +static inline Color DoColorBlendComponents( Color dst, Color src, const std::function& blend_func) { diff --git a/engine/src/flutter/impeller/geometry/color.h b/engine/src/flutter/impeller/geometry/color.h index 57c7c88e0c553..964bfd4eaa449 100644 --- a/engine/src/flutter/impeller/geometry/color.h +++ b/engine/src/flutter/impeller/geometry/color.h @@ -156,7 +156,7 @@ struct Color { } /// @brief Convert this color to a 32-bit representation. - static constexpr uint32_t ToIColor(Color color) { + static inline uint32_t ToIColor(Color color) { return (((std::lround(color.alpha * 255.0f) & 0xff) << 24) | ((std::lround(color.red * 255.0f) & 0xff) << 16) | ((std::lround(color.green * 255.0f) & 0xff) << 8) | @@ -243,7 +243,7 @@ struct Color { * * @return constexpr std::array */ - constexpr std::array ToR8G8B8A8() const { + inline std::array ToR8G8B8A8() const { uint8_t r = std::round(red * 255.0f); uint8_t g = std::round(green * 255.0f); uint8_t b = std::round(blue * 255.0f); @@ -256,7 +256,7 @@ struct Color { * * @return constexpr uint32_t */ - constexpr uint32_t ToARGB() const { + inline uint32_t ToARGB() const { std::array result = ToR8G8B8A8(); return result[3] << 24 | result[0] << 16 | result[1] << 8 | result[2]; } diff --git a/engine/src/flutter/impeller/geometry/matrix.h b/engine/src/flutter/impeller/geometry/matrix.h index eb032b292ba0e..a3a9da83a2ac0 100644 --- a/engine/src/flutter/impeller/geometry/matrix.h +++ b/engine/src/flutter/impeller/geometry/matrix.h @@ -320,7 +320,7 @@ struct Matrix { bool IsInvertible() const { return GetDeterminant() != 0; } - constexpr Scalar GetMaxBasisLengthXY() const { + inline Scalar GetMaxBasisLengthXY() const { // The full basis computation requires computing the squared scaling factor // for translate/scale only matrices. This substantially limits the range of // precision for small and large scales. Instead, check for the common cases @@ -338,17 +338,17 @@ struct Matrix { constexpr Vector3 GetBasisZ() const { return Vector3(m[8], m[9], m[10]); } - constexpr Vector3 GetScale() const { + inline Vector3 GetScale() const { return Vector3(GetBasisX().GetLength(), GetBasisY().GetLength(), GetBasisZ().GetLength()); } - constexpr Scalar GetDirectionScale(Vector3 direction) const { + inline Scalar GetDirectionScale(Vector3 direction) const { return 1.0f / (this->Basis().Invert() * direction.Normalize()).GetLength() * direction.GetLength(); } - constexpr bool IsFinite() const { + inline bool IsFinite() const { return vec[0].IsFinite() && vec[1].IsFinite() && vec[2].IsFinite() && vec[3].IsFinite(); } @@ -572,10 +572,10 @@ struct Matrix { return translate * scale; } - static constexpr Matrix MakePerspective(Radians fov_y, - Scalar aspect_ratio, - Scalar z_near, - Scalar z_far) { + static inline Matrix MakePerspective(Radians fov_y, + Scalar aspect_ratio, + Scalar z_near, + Scalar z_far) { Scalar height = std::tan(fov_y.radians * 0.5f); Scalar width = height * aspect_ratio; @@ -598,9 +598,9 @@ struct Matrix { z_near, z_far); } - static constexpr Matrix MakeLookAt(Vector3 position, - Vector3 target, - Vector3 up) { + static inline Matrix MakeLookAt(Vector3 position, + Vector3 target, + Vector3 up) { Vector3 forward = (target - position).Normalize(); Vector3 right = up.Cross(forward); up = forward.Cross(right); @@ -615,7 +615,7 @@ struct Matrix { // clang-format on } - static constexpr Vector2 CosSin(Radians radians) { + static inline Vector2 CosSin(Radians radians) { // The precision of a float around 1.0 is much lower than it is // around 0.0, so we end up with cases on quadrant rotations where // we get a +/-1.0 for one of the values and a non-zero value for diff --git a/engine/src/flutter/impeller/geometry/point.h b/engine/src/flutter/impeller/geometry/point.h index 2c19467c6439b..fc57dd93893a3 100644 --- a/engine/src/flutter/impeller/geometry/point.h +++ b/engine/src/flutter/impeller/geometry/point.h @@ -331,6 +331,14 @@ using UintPoint32 = TPoint; using Vector2 = Point; using Quad = std::array; +[[maybe_unused]] +static constexpr impeller::Vector2 kQuadrantAxes[4] = { + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {-1.0f, 0.0f}, + {0.0f, -1.0f}, +}; + #undef ONLY_ON_FLOAT #undef ONLY_ON_FLOAT_M diff --git a/engine/src/flutter/impeller/geometry/round_rect.h b/engine/src/flutter/impeller/geometry/round_rect.h index 9e5cd1a1bd9cf..b5a21da72acab 100644 --- a/engine/src/flutter/impeller/geometry/round_rect.h +++ b/engine/src/flutter/impeller/geometry/round_rect.h @@ -16,34 +16,34 @@ namespace impeller { struct RoundRect { RoundRect() = default; - constexpr static RoundRect MakeRect(const Rect& rect) { + inline static RoundRect MakeRect(const Rect& rect) { return MakeRectRadii(rect, RoundingRadii()); } - constexpr static RoundRect MakeOval(const Rect& rect) { + inline static RoundRect MakeOval(const Rect& rect) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(rect.GetSize() * 0.5f)); } - constexpr static RoundRect MakeRectRadius(const Rect& rect, Scalar radius) { + inline static RoundRect MakeRectRadius(const Rect& rect, Scalar radius) { return MakeRectRadii(rect, RoundingRadii::MakeRadius(radius)); } - constexpr static RoundRect MakeRectXY(const Rect& rect, - Scalar x_radius, - Scalar y_radius) { + inline static RoundRect MakeRectXY(const Rect& rect, + Scalar x_radius, + Scalar y_radius) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(Size(x_radius, y_radius))); } - constexpr static RoundRect MakeRectXY(const Rect& rect, Size corner_radii) { + inline static RoundRect MakeRectXY(const Rect& rect, Size corner_radii) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(corner_radii)); } - constexpr static RoundRect MakeNinePatch(const Rect& rect, - Scalar left, - Scalar top, - Scalar right, - Scalar bottom) { + inline static RoundRect MakeNinePatch(const Rect& rect, + Scalar left, + Scalar top, + Scalar right, + Scalar bottom) { return MakeRectRadii( rect, RoundingRadii::MakeNinePatch(left, top, right, bottom)); } @@ -51,6 +51,7 @@ struct RoundRect { static RoundRect MakeRectRadii(const Rect& rect, const RoundingRadii& radii); constexpr const Rect& GetBounds() const { return bounds_; } + constexpr const RoundingRadii& GetRadii() const { return radii_; } [[nodiscard]] constexpr bool IsFinite() const { @@ -85,7 +86,7 @@ struct RoundRect { [[nodiscard]] bool Contains(const Point& p) const; /// @brief Returns a new round rectangle translated by the given offset. - [[nodiscard]] constexpr RoundRect Shift(Scalar dx, Scalar dy) const { + [[nodiscard]] inline RoundRect Shift(Scalar dx, Scalar dy) const { // Just in case, use the factory rather than the internal constructor // as shifting the rectangle may increase/decrease its bit precision // so we should re-validate the radii to the newly located rectangle. @@ -94,10 +95,10 @@ struct RoundRect { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundRect Expand(Scalar left, - Scalar top, - Scalar right, - Scalar bottom) const { + [[nodiscard]] inline RoundRect Expand(Scalar left, + Scalar top, + Scalar right, + Scalar bottom) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. @@ -106,8 +107,8 @@ struct RoundRect { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundRect Expand(Scalar horizontal, - Scalar vertical) const { + [[nodiscard]] inline RoundRect Expand(Scalar horizontal, + Scalar vertical) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. @@ -116,7 +117,7 @@ struct RoundRect { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundRect Expand(Scalar amount) const { + [[nodiscard]] inline RoundRect Expand(Scalar amount) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. diff --git a/engine/src/flutter/impeller/geometry/round_superellipse.cc b/engine/src/flutter/impeller/geometry/round_superellipse.cc index b47533c84b459..ac474983ff859 100644 --- a/engine/src/flutter/impeller/geometry/round_superellipse.cc +++ b/engine/src/flutter/impeller/geometry/round_superellipse.cc @@ -38,4 +38,29 @@ RoundRect RoundSuperellipse::ToApproximateRoundRect() const { return RoundRect::MakeRectRadii(GetBounds(), GetRadii()); } +RoundSuperellipsePathSource::RoundSuperellipsePathSource( + const RoundSuperellipse& round_superellipse) + : round_superellipse_(round_superellipse) {} + +RoundSuperellipsePathSource::~RoundSuperellipsePathSource() = default; + +FillType RoundSuperellipsePathSource::GetFillType() const { + return FillType::kNonZero; +} + +Rect RoundSuperellipsePathSource::GetBounds() const { + return round_superellipse_.GetBounds(); +} + +bool RoundSuperellipsePathSource::IsConvex() const { + return true; +} + +void RoundSuperellipsePathSource::Dispatch(PathReceiver& receiver) const { + auto param = RoundSuperellipseParam::MakeBoundsRadii( + round_superellipse_.GetBounds(), round_superellipse_.GetRadii()); + param.Dispatch(receiver); + receiver.PathEnd(); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/round_superellipse.h b/engine/src/flutter/impeller/geometry/round_superellipse.h index 12fe74a413014..83c4c3e914b72 100644 --- a/engine/src/flutter/impeller/geometry/round_superellipse.h +++ b/engine/src/flutter/impeller/geometry/round_superellipse.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ #define FLUTTER_IMPELLER_GEOMETRY_ROUND_SUPERELLIPSE_H_ +#include "flutter/impeller/geometry/path_source.h" #include "flutter/impeller/geometry/point.h" #include "flutter/impeller/geometry/rect.h" #include "flutter/impeller/geometry/rounding_radii.h" @@ -17,28 +18,28 @@ struct RoundRect; struct RoundSuperellipse { RoundSuperellipse() = default; - constexpr static RoundSuperellipse MakeRect(const Rect& rect) { + inline static RoundSuperellipse MakeRect(const Rect& rect) { return MakeRectRadii(rect, RoundingRadii()); } - constexpr static RoundSuperellipse MakeOval(const Rect& rect) { + inline static RoundSuperellipse MakeOval(const Rect& rect) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(rect.GetSize() * 0.5f)); } - constexpr static RoundSuperellipse MakeRectRadius(const Rect& rect, - Scalar radius) { + inline static RoundSuperellipse MakeRectRadius(const Rect& rect, + Scalar radius) { return MakeRectRadii(rect, RoundingRadii::MakeRadius(radius)); } - constexpr static RoundSuperellipse MakeRectXY(const Rect& rect, - Scalar x_radius, - Scalar y_radius) { + inline static RoundSuperellipse MakeRectXY(const Rect& rect, + Scalar x_radius, + Scalar y_radius) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(Size(x_radius, y_radius))); } - constexpr static RoundSuperellipse MakeRectXY(const Rect& rect, - Size corner_radii) { + inline static RoundSuperellipse MakeRectXY(const Rect& rect, + Size corner_radii) { return MakeRectRadii(rect, RoundingRadii::MakeRadii(corner_radii)); } @@ -80,7 +81,7 @@ struct RoundSuperellipse { [[nodiscard]] bool Contains(const Point& p) const; /// @brief Returns a new round rectangle translated by the given offset. - [[nodiscard]] constexpr RoundSuperellipse Shift(Scalar dx, Scalar dy) const { + [[nodiscard]] inline RoundSuperellipse Shift(Scalar dx, Scalar dy) const { // Just in case, use the factory rather than the internal constructor // as shifting the rectangle may increase/decrease its bit precision // so we should re-validate the radii to the newly located rectangle. @@ -89,10 +90,10 @@ struct RoundSuperellipse { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundSuperellipse Expand(Scalar left, - Scalar top, - Scalar right, - Scalar bottom) const { + [[nodiscard]] inline RoundSuperellipse Expand(Scalar left, + Scalar top, + Scalar right, + Scalar bottom) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. @@ -101,8 +102,8 @@ struct RoundSuperellipse { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundSuperellipse Expand(Scalar horizontal, - Scalar vertical) const { + [[nodiscard]] inline RoundSuperellipse Expand(Scalar horizontal, + Scalar vertical) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. @@ -111,7 +112,7 @@ struct RoundSuperellipse { /// @brief Returns a round rectangle with expanded edges. Negative expansion /// results in shrinking. - [[nodiscard]] constexpr RoundSuperellipse Expand(Scalar amount) const { + [[nodiscard]] inline RoundSuperellipse Expand(Scalar amount) const { // Use the factory rather than the internal constructor as the changing // size of the rectangle requires that we re-validate the radii to the // newly sized rectangle. @@ -142,6 +143,33 @@ struct RoundSuperellipse { RoundingRadii radii_; }; +class RoundSuperellipsePathSource : public PathSource { + public: + explicit RoundSuperellipsePathSource( + const RoundSuperellipse& round_superellipse); + + ~RoundSuperellipsePathSource(); + + const RoundSuperellipse& GetRoundSuperellipse() const { + return round_superellipse_; + } + + // |PathSource| + FillType GetFillType() const override; + + // |PathSource| + Rect GetBounds() const override; + + // |PathSource| + bool IsConvex() const override; + + // |PathSource| + void Dispatch(PathReceiver& receiver) const override; + + private: + const RoundSuperellipse round_superellipse_; +}; + } // namespace impeller namespace std { diff --git a/engine/src/flutter/impeller/geometry/round_superellipse_param.cc b/engine/src/flutter/impeller/geometry/round_superellipse_param.cc index 0f0f0c787313d..21c75be3bd807 100644 --- a/engine/src/flutter/impeller/geometry/round_superellipse_param.cc +++ b/engine/src/flutter/impeller/geometry/round_superellipse_param.cc @@ -519,7 +519,7 @@ RoundSuperellipseParam RoundSuperellipseParam::MakeBoundsRadii( }; } -void RoundSuperellipseParam::AddToPath(PathReceiver& path_receiver) const { +void RoundSuperellipseParam::Dispatch(PathReceiver& path_receiver) const { RoundSuperellipseBuilder builder(path_receiver); Point start = top_right.offset + diff --git a/engine/src/flutter/impeller/geometry/round_superellipse_param.h b/engine/src/flutter/impeller/geometry/round_superellipse_param.h index 06e90d7f13517..602b600dab43f 100644 --- a/engine/src/flutter/impeller/geometry/round_superellipse_param.h +++ b/engine/src/flutter/impeller/geometry/round_superellipse_param.h @@ -110,8 +110,8 @@ struct RoundSuperellipseParam { // with the bounds, which is recommended for callers. bool Contains(const Point& point) const; - // Add a path of this rounded superellipse to the provided path builder. - void AddToPath(PathReceiver& path) const; + // Dispatch the path operations of this rounded superellipse to the receiver. + void Dispatch(PathReceiver& receiver) const; // A factor used to calculate the "gap", defined as the distance from the // midpoint of the curved corners to the nearest sides of the bounding box. diff --git a/engine/src/flutter/impeller/geometry/rstransform.h b/engine/src/flutter/impeller/geometry/rstransform.h index 28b4cd09b4525..d92bd3379d6e1 100644 --- a/engine/src/flutter/impeller/geometry/rstransform.h +++ b/engine/src/flutter/impeller/geometry/rstransform.h @@ -35,9 +35,7 @@ struct RSTransform { /// Constructs an RSTransform from the indicated origin, uniform scale, /// and radians rotation. - static constexpr RSTransform Make(Point origin, - Scalar scale, - Radians radians) { + static inline RSTransform Make(Point origin, Scalar scale, Radians radians) { auto scaled_cos_sin = Matrix::CosSin(radians) * scale; return {scaled_cos_sin.x, scaled_cos_sin.y, origin.x, origin.y}; } diff --git a/engine/src/flutter/impeller/geometry/scalar.h b/engine/src/flutter/impeller/geometry/scalar.h index dadc52850cb5f..10e8e66ea6455 100644 --- a/engine/src/flutter/impeller/geometry/scalar.h +++ b/engine/src/flutter/impeller/geometry/scalar.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_GEOMETRY_SCALAR_H_ #include +#include #include #include @@ -46,6 +47,30 @@ struct Radians { constexpr Radians() = default; explicit constexpr Radians(Scalar p_radians) : radians(p_radians) {} + + constexpr bool IsFinite() const { return std::isfinite(radians); } + + constexpr Radians operator-() { return Radians{-radians}; } + + constexpr Radians operator+(Radians r) { + return Radians{radians + r.radians}; + } + + constexpr Radians operator-(Radians r) { + return Radians{radians - r.radians}; + } + + constexpr bool operator>(Radians r) { return radians > r.radians; } + + constexpr bool operator>=(Radians r) { return radians >= r.radians; } + + constexpr bool operator==(Radians r) { return radians == r.radians; } + + constexpr bool operator!=(Radians r) { return radians != r.radians; } + + constexpr bool operator<=(Radians r) { return radians <= r.radians; } + + constexpr bool operator<(Radians r) { return radians < r.radians; } }; struct Degrees { @@ -58,10 +83,54 @@ struct Degrees { constexpr operator Radians() const { return Radians{degrees * kPi / 180.0f}; }; + + constexpr bool IsFinite() const { return std::isfinite(degrees); } + + constexpr Degrees operator-() const { return Degrees{-degrees}; } + + constexpr Degrees operator+(Degrees d) const { + return Degrees{degrees + d.degrees}; + } + + constexpr Degrees operator-(Degrees d) const { + return Degrees{degrees - d.degrees}; + } + + constexpr bool operator>(Degrees d) { return degrees > d.degrees; } + + constexpr bool operator>=(Degrees d) { return degrees >= d.degrees; } + + constexpr bool operator==(Degrees d) { return degrees == d.degrees; } + + constexpr bool operator!=(Degrees d) { return degrees != d.degrees; } + + constexpr bool operator<=(Degrees d) { return degrees <= d.degrees; } + + constexpr bool operator<(Degrees d) { return degrees < d.degrees; } + + constexpr Degrees GetPositive() const { + Scalar deg = std::fmod(degrees, 360.0f); + if (deg < 0.0f) { + deg += 360.0f; + } + return Degrees{deg}; + } }; // NOLINTEND(google-explicit-constructor) } // namespace impeller +namespace std { + +inline std::ostream& operator<<(std::ostream& out, const impeller::Degrees& d) { + return out << "Degrees(" << d.degrees << ")"; +} + +inline std::ostream& operator<<(std::ostream& out, const impeller::Radians& r) { + return out << "Radians(" << r.radians << ")"; +} + +} // namespace std + #endif // FLUTTER_IMPELLER_GEOMETRY_SCALAR_H_ diff --git a/engine/src/flutter/impeller/geometry/vector.h b/engine/src/flutter/impeller/geometry/vector.h index 0f1c4dc10681e..2128bb1513e96 100644 --- a/engine/src/flutter/impeller/geometry/vector.h +++ b/engine/src/flutter/impeller/geometry/vector.h @@ -44,9 +44,9 @@ struct Vector3 { * * @return the calculated length. */ - constexpr Scalar GetLength() const { return sqrt(x * x + y * y + z * z); } + inline Scalar GetLength() const { return sqrt(x * x + y * y + z * z); } - constexpr Vector3 Normalize() const { + inline Vector3 Normalize() const { const auto len = GetLength(); return {x / len, y / len, z / len}; } @@ -55,7 +55,7 @@ struct Vector3 { return ((x * other.x) + (y * other.y) + (z * other.z)); } - constexpr Vector3 Abs() const { + inline Vector3 Abs() const { return {std::fabs(x), std::fabs(y), std::fabs(z)}; } @@ -67,23 +67,23 @@ struct Vector3 { }; } - constexpr Vector3 Min(const Vector3& p) const { + inline Vector3 Min(const Vector3& p) const { return {std::min(x, p.x), std::min(y, p.y), std::min(z, p.z)}; } - constexpr Vector3 Max(const Vector3& p) const { + inline Vector3 Max(const Vector3& p) const { return {std::max(x, p.x), std::max(y, p.y), std::max(z, p.z)}; } - constexpr Vector3 Floor() const { + inline Vector3 Floor() const { return {std::floor(x), std::floor(y), std::floor(z)}; } - constexpr Vector3 Ceil() const { + inline Vector3 Ceil() const { return {std::ceil(x), std::ceil(y), std::ceil(z)}; } - constexpr Vector3 Round() const { + inline Vector3 Round() const { return {std::round(x), std::round(y), std::round(z)}; } @@ -255,7 +255,7 @@ struct Vector4 { constexpr Vector4(std::array values) : x(values[0]), y(values[1]), z(values[2]), w(values[3]) {} - constexpr bool IsFinite() const { + inline bool IsFinite() const { return std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && std::isfinite(w); } @@ -299,15 +299,15 @@ struct Vector4 { std::max(w, p.w)}; } - constexpr Vector4 Floor() const { + inline Vector4 Floor() const { return {std::floor(x), std::floor(y), std::floor(z), std::floor(w)}; } - constexpr Vector4 Ceil() const { + inline Vector4 Ceil() const { return {std::ceil(x), std::ceil(y), std::ceil(z), std::ceil(w)}; } - constexpr Vector4 Round() const { + inline Vector4 Round() const { return {std::round(x), std::round(y), std::round(z), std::round(w)}; } diff --git a/engine/src/flutter/impeller/geometry/wangs_formula.cc b/engine/src/flutter/impeller/geometry/wangs_formula.cc index 2e02e9451c0dd..5cae9c67b7c48 100644 --- a/engine/src/flutter/impeller/geometry/wangs_formula.cc +++ b/engine/src/flutter/impeller/geometry/wangs_formula.cc @@ -13,7 +13,7 @@ namespace { // X and Y directions. constexpr static Scalar kPrecision = 4; -constexpr Scalar length(Point n) { +inline Scalar length(Point n) { Point nn = n * n; return std::sqrt(nn.x + nn.y); } diff --git a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc index a6e6e3b66d3f4..a49cac03a61ca 100644 --- a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc +++ b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc @@ -132,6 +132,11 @@ void GoldenPlaygroundTest::SetTypographerContext( void GoldenPlaygroundTest::TearDown() { ASSERT_FALSE(dlopen("/usr/local/lib/libMoltenVK.dylib", RTLD_NOLOAD)); + + auto context = GetContext(); + if (context) { + context->DisposeThreadLocalCachedResources(); + } } namespace { @@ -280,6 +285,9 @@ RuntimeStage::Map GoldenPlaygroundTest::OpenAssetAsRuntimeStage( } std::shared_ptr GoldenPlaygroundTest::GetContext() const { + if (!pimpl_->screenshotter) { + return nullptr; + } return pimpl_->screenshotter->GetPlayground().GetContext(); } diff --git a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h index 0935e5c816e27..2028a82529ba4 100644 --- a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h +++ b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h @@ -38,7 +38,7 @@ class PlaygroundImplMTL final : public PlaygroundImpl { std::shared_ptr context_; std::shared_ptr concurrent_loop_; std::shared_ptr swapchain_transients_; - std::shared_ptr is_gpu_disabled_sync_switch_; + std::shared_ptr is_gpu_disabled_sync_switch_; // |PlaygroundImpl| std::shared_ptr GetContext() const override; @@ -50,6 +50,9 @@ class PlaygroundImplMTL final : public PlaygroundImpl { std::unique_ptr AcquireSurfaceFrame( std::shared_ptr context) override; + // |PlaygroundImpl| + void SetGPUDisabled(bool disabled) const override; + PlaygroundImplMTL(const PlaygroundImplMTL&) = delete; PlaygroundImplMTL& operator=(const PlaygroundImplMTL&) = delete; diff --git a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm index 978f01ab416fd..a276c11aeaa69 100644 --- a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -138,4 +138,8 @@ return fml::Status(); } +void PlaygroundImplMTL::SetGPUDisabled(bool disabled) const { + is_gpu_disabled_sync_switch_->SetSwitch(disabled); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.cc b/engine/src/flutter/impeller/playground/playground.cc index 3889d6d68d166..4b6d786c3021c 100644 --- a/engine/src/flutter/impeller/playground/playground.cc +++ b/engine/src/flutter/impeller/playground/playground.cc @@ -527,4 +527,8 @@ Playground::VKProcAddressResolver Playground::CreateVKProcAddressResolver() return impl_->CreateVKProcAddressResolver(); } +void Playground::SetGPUDisabled(bool value) const { + impl_->SetGPUDisabled(value); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.h b/engine/src/flutter/impeller/playground/playground.h index 236e6de89c649..6878a5975156c 100644 --- a/engine/src/flutter/impeller/playground/playground.h +++ b/engine/src/flutter/impeller/playground/playground.h @@ -122,6 +122,11 @@ class Playground { std::function; VKProcAddressResolver CreateVKProcAddressResolver() const; + /// @brief Mark the GPU as unavilable. + /// + /// Only supported on the Metal backend. + void SetGPUDisabled(bool disabled) const; + protected: const PlaygroundSwitches switches_; diff --git a/engine/src/flutter/impeller/playground/playground_impl.h b/engine/src/flutter/impeller/playground/playground_impl.h index 387a2cb5af44e..ed2593fc98ffb 100644 --- a/engine/src/flutter/impeller/playground/playground_impl.h +++ b/engine/src/flutter/impeller/playground/playground_impl.h @@ -40,6 +40,8 @@ class PlaygroundImpl { virtual Playground::VKProcAddressResolver CreateVKProcAddressResolver() const; + virtual void SetGPUDisabled(bool disabled) const {} + protected: const PlaygroundSwitches switches_; diff --git a/engine/src/flutter/impeller/renderer/backend/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/BUILD.gn index 2f6b15b0d9a55..2c4dfde5b706f 100644 --- a/engine/src/flutter/impeller/renderer/backend/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/BUILD.gn @@ -13,12 +13,12 @@ group("backend") { } if (impeller_enable_opengles) { - assert(is_mac || is_linux || is_win || is_android) + assert(is_mac || is_linux || is_win || is_android || is_qnx) public_deps += [ "gles" ] } if (impeller_enable_vulkan) { - assert(is_mac || is_linux || is_win || is_android) + assert(is_mac || is_linux || is_win || is_android || is_qnx) public_deps += [ "vulkan" ] } } diff --git a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc index c824a16be8504..0aa7cefde5ab8 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc @@ -7,31 +7,8 @@ #include "impeller/core/formats.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" -#ifdef FML_OS_ANDROID -#include -#endif // FML_OS_ANDROID - namespace impeller { -namespace { -// Workaround for crashes in Vivante GL driver on Android. -// -// See: -// * https://github.com/flutter/flutter/issues/167850 -// * http://crbug.com/141785 -#ifdef FML_OS_ANDROID -bool IsVivante() { - char product_model[PROP_VALUE_MAX]; - __system_property_get("ro.hardware.egl", product_model); - return strcmp(product_model, "VIVANTE") == 0; -} -#else -bool IsVivante() { - return false; -} -#endif // FML_OS_ANDROID -} // namespace - // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_shader_framebuffer_fetch.txt static const constexpr char* kFramebufferFetchExt = "GL_EXT_shader_framebuffer_fetch"; @@ -147,7 +124,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) { supports_decal_sampler_address_mode_ = true; } - if (desc->HasExtension(kMultisampledRenderToTextureExt) && !IsVivante()) { + if (desc->HasExtension(kMultisampledRenderToTextureExt)) { supports_implicit_msaa_ = true; if (desc->HasExtension(kMultisampledRenderToTexture2Ext)) { diff --git a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn index ac4a000492232..9103010bd1d60 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn @@ -70,6 +70,7 @@ impeller_component("metal_unittests") { sources = [ "allocator_mtl_unittests.mm", + "context_mtl_unittests.mm", "swapchain_transients_mtl_unittests.mm", "texture_mtl_unittests.mm", ] diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h index 712cf7c1f69da..348830d0fe7ee 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h @@ -146,6 +146,9 @@ class ContextMTL final : public Context, void StoreTaskForGPU(const fml::closure& task, const fml::closure& failure) override; + // visible for testing. + void FlushTasksAwaitingGPU(); + private: class SyncSwitchObserver : public fml::SyncSwitch::Observer { public: @@ -191,8 +194,6 @@ class ContextMTL final : public Context, std::shared_ptr CreateCommandBufferInQueue( id queue) const; - void FlushTasksAwaitingGPU(); - ContextMTL(const ContextMTL&) = delete; ContextMTL& operator=(const ContextMTL&) = delete; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index b30896f2b5d5b..b64547b93f248 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -418,8 +418,26 @@ new ContextMTL(flags, device, command_queue, Lock lock(tasks_awaiting_gpu_mutex_); std::swap(tasks_awaiting_gpu, tasks_awaiting_gpu_); } + std::vector tasks_to_queue; for (const auto& task : tasks_awaiting_gpu) { - task.task(); + is_gpu_disabled_sync_switch_->Execute(fml::SyncSwitch::Handlers() + .SetIfFalse([&] { task.task(); }) + .SetIfTrue([&] { + // Lost access to the GPU + // immediately after it was + // activated. This may happen if + // the app was quickly + // foregrounded/backgrounded + // from a push notification. + // Store the tasks on the + // context again. + tasks_to_queue.push_back(task); + })); + } + if (!tasks_to_queue.empty()) { + Lock lock(tasks_awaiting_gpu_mutex_); + tasks_awaiting_gpu_.insert(tasks_awaiting_gpu_.end(), + tasks_to_queue.begin(), tasks_to_queue.end()); } } diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm new file mode 100644 index 0000000000000..cb3ee72e599f7 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter 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/testing/testing.h" +#include "impeller/core/device_buffer_descriptor.h" +#include "impeller/core/formats.h" +#include "impeller/core/texture_descriptor.h" +#include "impeller/playground/playground_test.h" +#include "impeller/renderer/backend/metal/allocator_mtl.h" +#include "impeller/renderer/backend/metal/context_mtl.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/backend/metal/texture_mtl.h" +#include "impeller/renderer/capabilities.h" + +#include +#include +#include + +#include "gtest/gtest.h" + +namespace impeller { +namespace testing { + +using ContextMTLTest = PlaygroundTest; +INSTANTIATE_METAL_PLAYGROUND_SUITE(ContextMTLTest); + +TEST_P(ContextMTLTest, FlushTask) { + auto& context_mtl = ContextMTL::Cast(*GetContext()); + + int executed = 0; + int failed = 0; + context_mtl.StoreTaskForGPU([&]() { executed++; }, [&]() { failed++; }); + + context_mtl.FlushTasksAwaitingGPU(); + + EXPECT_EQ(executed, 1); + EXPECT_EQ(failed, 0); +} + +TEST_P(ContextMTLTest, FlushTaskWithGPULoss) { + auto& context_mtl = ContextMTL::Cast(*GetContext()); + + int executed = 0; + int failed = 0; + context_mtl.StoreTaskForGPU([&]() { executed++; }, [&]() { failed++; }); + + // If tasks are flushed while the GPU is disabled, then + // they should not be executed. + SetGPUDisabled(/*disabled=*/true); + context_mtl.FlushTasksAwaitingGPU(); + + EXPECT_EQ(executed, 0); + EXPECT_EQ(failed, 0); + + // Toggling availibility should flush tasks. + SetGPUDisabled(/*disabled=*/false); + + EXPECT_EQ(executed, 1); + EXPECT_EQ(failed, 0); +} + +} // namespace testing +} // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc index 1db355a9a0ad7..f5ae5d62e3cb2 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -269,8 +269,9 @@ CapabilitiesVK::GetEnabledDeviceExtensions( } exts = maybe_exts.value(); } else { - exts = std::set(embedder_device_extensions_.begin(), - embedder_device_extensions_.end()); + for (const auto& ext : embedder_device_extensions_) { + exts.insert(ext); + } } std::vector enabled; @@ -580,8 +581,9 @@ bool CapabilitiesVK::SetPhysicalDevice( } exts = maybe_exts.value(); } else { - exts = std::set(embedder_device_extensions_.begin(), - embedder_device_extensions_.end()); + for (const auto& ext : embedder_device_extensions_) { + exts.insert(ext); + } } IterateExtensions([&](auto ext) -> bool { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc index d6176b2c3b808..dfa80c252b486 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc @@ -171,10 +171,23 @@ static thread_local std::unique_ptr tls_command_pool_map; // with that context. static Mutex g_all_pools_map_mutex; static std::unordered_map< - const ContextVK*, - std::vector>> g_all_pools_map + uint64_t, + std::unordered_map>> g_all_pools_map IPLR_GUARDED_BY(g_all_pools_map_mutex); +CommandPoolRecyclerVK::CommandPoolRecyclerVK( + const std::shared_ptr& context) + : context_(context), context_hash_(context->GetHash()) {} + +// Visible for testing. +// Returns the number of pools in g_all_pools_map for the given context. +int CommandPoolRecyclerVK::GetGlobalPoolCount(const ContextVK& context) { + Lock all_pools_lock(g_all_pools_map_mutex); + auto it = g_all_pools_map.find(context.GetHash()); + return it != g_all_pools_map.end() ? it->second.size() : 0; +} + // TODO(matanlurey): Return a status_or<> instead of nullptr when we have one. std::shared_ptr CommandPoolRecyclerVK::Get() { auto const strong_context = context_.lock(); @@ -187,8 +200,7 @@ std::shared_ptr CommandPoolRecyclerVK::Get() { tls_command_pool_map.reset(new CommandPoolMap()); } CommandPoolMap& pool_map = *tls_command_pool_map.get(); - auto const hash = strong_context->GetHash(); - auto const it = pool_map.find(hash); + auto const it = pool_map.find(context_hash_); if (it != pool_map.end()) { return it->second; } @@ -201,11 +213,11 @@ std::shared_ptr CommandPoolRecyclerVK::Get() { auto const resource = std::make_shared( std::move(data->pool), std::move(data->buffers), context_); - pool_map.emplace(hash, resource); + pool_map.emplace(context_hash_, resource); { Lock all_pools_lock(g_all_pools_map_mutex); - g_all_pools_map[strong_context.get()].push_back(resource); + g_all_pools_map[context_hash_][std::this_thread::get_id()] = resource; } return resource; @@ -275,30 +287,33 @@ void CommandPoolRecyclerVK::Reclaim( RecycledData{.pool = std::move(pool), .buffers = std::move(buffers)}); } -CommandPoolRecyclerVK::~CommandPoolRecyclerVK() { - // Ensure all recycled pools are reclaimed before this is destroyed. - Dispose(); -} - void CommandPoolRecyclerVK::Dispose() { CommandPoolMap* pool_map = tls_command_pool_map.get(); if (pool_map) { - pool_map->clear(); + pool_map->erase(context_hash_); + } + + { + Lock all_pools_lock(g_all_pools_map_mutex); + auto found = g_all_pools_map.find(context_hash_); + if (found != g_all_pools_map.end()) { + found->second.erase(std::this_thread::get_id()); + } } } -void CommandPoolRecyclerVK::DestroyThreadLocalPools(const ContextVK* context) { +void CommandPoolRecyclerVK::DestroyThreadLocalPools() { // Delete the context's entry in this thread's command pool map. if (tls_command_pool_map.get()) { - tls_command_pool_map.get()->erase(context->GetHash()); + tls_command_pool_map.get()->erase(context_hash_); } // Destroy all other thread-local CommandPoolVK instances associated with // this context. Lock all_pools_lock(g_all_pools_map_mutex); - auto found = g_all_pools_map.find(context); + auto found = g_all_pools_map.find(context_hash_); if (found != g_all_pools_map.end()) { - for (auto& weak_pool : found->second) { + for (auto& [thread_id, weak_pool] : found->second) { auto pool = weak_pool.lock(); if (!pool) { continue; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h index 30f2b3c3688ae..1fc9d06b32fb4 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h @@ -103,8 +103,6 @@ class CommandPoolVK final { class CommandPoolRecyclerVK final : public std::enable_shared_from_this { public: - ~CommandPoolRecyclerVK(); - /// A unique command pool and zero or more recycled command buffers. struct RecycledData { vk::UniqueCommandPool pool; @@ -112,16 +110,13 @@ class CommandPoolRecyclerVK final }; /// @brief Clean up resources held by all per-thread command pools - /// associated with the given context. - /// - /// @param[in] context The context. - static void DestroyThreadLocalPools(const ContextVK* context); + /// associated with the context. + void DestroyThreadLocalPools(); /// @brief Creates a recycler for the given |ContextVK|. /// /// @param[in] context The context to create the recycler for. - explicit CommandPoolRecyclerVK(std::weak_ptr context) - : context_(std::move(context)) {} + explicit CommandPoolRecyclerVK(const std::shared_ptr& context); /// @brief Gets a command pool for the current thread. /// @@ -137,11 +132,15 @@ class CommandPoolRecyclerVK final std::vector&& buffers, bool should_trim = false); - /// @brief Clears all recycled command pools to let them be reclaimed. + /// @brief Clears this context's thread-local command pool. void Dispose(); + // Visible for testing. + static int GetGlobalPoolCount(const ContextVK& context); + private: std::weak_ptr context_; + uint64_t context_hash_; Mutex recycled_mutex_; std::vector recycled_ IPLR_GUARDED_BY(recycled_mutex_); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc index 42da1b896e50f..98f221ac95b1c 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc @@ -71,6 +71,37 @@ class DeathRattle final { std::function callback_; }; +// Wait for reclaim of recycled command pools. +void WaitForReclaim(const std::shared_ptr& context) { + // Add a resource to the resource manager and wait for its destructor to + // signal an event. + // + // This must be done twice because the resource manager does not guarantee + // the order in which resources are handled within the set of reclaimable + // resources. When the first DeathRattle is signaled there may be pools + // within the pending set that have not yet been reclaimed. After the second + // DeathRattle is signaled all resources in the original set will have been + // reclaimed. + for (int i = 0; i < 2; i++) { + auto waiter = fml::AutoResetWaitableEvent(); + auto rattle = DeathRattle([&waiter]() { waiter.Signal(); }); + { + UniqueResourceVKT resource(context->GetResourceManager(), + std::move(rattle)); + } + waiter.Wait(); + } +} + +// The list of function calls returned by the mock Vulkan device is not thread +// safe. Wait for the background thread to finish any pending reclaim +// operations before obtaining the list. +std::shared_ptr> ReclaimAndGetMockVulkanFunctions( + const std::shared_ptr& context) { + WaitForReclaim(context); + return GetMockVulkanFunctions(context->GetDevice()); +} + } // namespace TEST(CommandPoolRecyclerVKTest, ReclaimMakesCommandPoolAvailable) { @@ -85,16 +116,7 @@ TEST(CommandPoolRecyclerVKTest, ReclaimMakesCommandPoolAvailable) { recycler->Dispose(); } - // Add something to the resource manager and have it notify us when it's - // destroyed. That should give us a non-flaky signal that the pool has been - // reclaimed as well. - auto waiter = fml::AutoResetWaitableEvent(); - auto rattle = DeathRattle([&waiter]() { waiter.Signal(); }); - { - UniqueResourceVKT resource(context->GetResourceManager(), - std::move(rattle)); - } - waiter.Wait(); + WaitForReclaim(context); // On another thread explicitly, request a new pool. std::thread thread([&]() { @@ -105,7 +127,7 @@ TEST(CommandPoolRecyclerVKTest, ReclaimMakesCommandPoolAvailable) { thread.join(); // Now check that we only ever created one pool. - auto const called = GetMockVulkanFunctions(context->GetDevice()); + auto const called = ReclaimAndGetMockVulkanFunctions(context); EXPECT_EQ(std::count(called->begin(), called->end(), "vkCreateCommandPool"), 1u); @@ -127,16 +149,7 @@ TEST(CommandPoolRecyclerVKTest, CommandBuffersAreRecycled) { recycler->Dispose(); } - // Wait for the pool to be reclaimed. - for (auto i = 0u; i < 2u; i++) { - auto waiter = fml::AutoResetWaitableEvent(); - auto rattle = DeathRattle([&waiter]() { waiter.Signal(); }); - { - UniqueResourceVKT resource(context->GetResourceManager(), - std::move(rattle)); - } - waiter.Wait(); - } + WaitForReclaim(context); { // Create a second pool and command buffer, which should reused the existing @@ -152,7 +165,7 @@ TEST(CommandPoolRecyclerVKTest, CommandBuffersAreRecycled) { } // Now check that we only ever created one pool and one command buffer. - auto const called = GetMockVulkanFunctions(context->GetDevice()); + auto const called = ReclaimAndGetMockVulkanFunctions(context); EXPECT_EQ(std::count(called->begin(), called->end(), "vkCreateCommandPool"), 1u); EXPECT_EQ( @@ -180,19 +193,8 @@ TEST(CommandPoolRecyclerVKTest, ExtraCommandBufferAllocationsTriggerTrim) { recycler->Dispose(); } - // Wait for the pool to be reclaimed. - for (auto i = 0u; i < 2u; i++) { - auto waiter = fml::AutoResetWaitableEvent(); - auto rattle = DeathRattle([&waiter]() { waiter.Signal(); }); - { - UniqueResourceVKT resource(context->GetResourceManager(), - std::move(rattle)); - } - waiter.Wait(); - } - // Command pool is reset but does not release resources. - auto called = GetMockVulkanFunctions(context->GetDevice()); + auto called = ReclaimAndGetMockVulkanFunctions(context); EXPECT_EQ(std::count(called->begin(), called->end(), "vkResetCommandPool"), 1u); @@ -206,21 +208,10 @@ TEST(CommandPoolRecyclerVKTest, ExtraCommandBufferAllocationsTriggerTrim) { recycler->Dispose(); } - // Wait for the pool to be reclaimed. - for (auto i = 0u; i < 2u; i++) { - auto waiter = fml::AutoResetWaitableEvent(); - auto rattle = DeathRattle([&waiter]() { waiter.Signal(); }); - { - UniqueResourceVKT resource(context->GetResourceManager(), - std::move(rattle)); - } - waiter.Wait(); - } - // Verify that the cmd pool was trimmed. // Now check that we only ever created one pool and one command buffer. - called = GetMockVulkanFunctions(context->GetDevice()); + called = ReclaimAndGetMockVulkanFunctions(context); EXPECT_EQ(std::count(called->begin(), called->end(), "vkResetCommandPoolReleaseResources"), 1u); @@ -228,5 +219,24 @@ TEST(CommandPoolRecyclerVKTest, ExtraCommandBufferAllocationsTriggerTrim) { context->Shutdown(); } +TEST(CommandPoolRecyclerVKTest, RecyclerGlobalPoolMapSize) { + auto context = MockVulkanContextBuilder().Build(); + auto const recycler = context->GetCommandPoolRecycler(); + + // The global pool list for this context should initially be empty. + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 0); + + // Creating a pool for this thread should insert the pool into the global map. + auto pool = recycler->Get(); + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 1); + + // Disposing this thread's pool should remove it from the global map. + pool.reset(); + recycler->Dispose(); + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 0); + + context->Shutdown(); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 6066065ca2b34..a9a42ad35a560 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -134,7 +134,9 @@ ContextVK::~ContextVK() { if (device_holder_ && device_holder_->device) { [[maybe_unused]] auto result = device_holder_->device->waitIdle(); } - CommandPoolRecyclerVK::DestroyThreadLocalPools(this); + if (command_pool_recycler_) { + command_pool_recycler_->DestroyThreadLocalPools(); + } } Context::BackendType ContextVK::GetBackendType() const { @@ -421,7 +423,7 @@ void ContextVK::Setup(Settings settings) { } auto command_pool_recycler = - std::make_shared(weak_from_this()); + std::make_shared(shared_from_this()); if (!command_pool_recycler) { VALIDATION_LOG << "Could not create command pool recycler."; return; diff --git a/engine/src/flutter/impeller/renderer/pipeline_library.h b/engine/src/flutter/impeller/renderer/pipeline_library.h index f44b4e1dbb503..4c5a8617d0bcd 100644 --- a/engine/src/flutter/impeller/renderer/pipeline_library.h +++ b/engine/src/flutter/impeller/renderer/pipeline_library.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_RENDERER_PIPELINE_LIBRARY_H_ #include +#include #include "compute_pipeline_descriptor.h" #include "impeller/renderer/pipeline.h" diff --git a/engine/src/flutter/impeller/shader_archive/shader_archive_writer.cc b/engine/src/flutter/impeller/shader_archive/shader_archive_writer.cc index 83c0459f34ebe..070c5c23d7621 100644 --- a/engine/src/flutter/impeller/shader_archive/shader_archive_writer.cc +++ b/engine/src/flutter/impeller/shader_archive/shader_archive_writer.cc @@ -8,6 +8,7 @@ #include #include +#include "flutter/fml/build_config.h" #include "impeller/shader_archive/shader_archive_flatbuffers.h" namespace impeller { @@ -18,6 +19,9 @@ ShaderArchiveWriter::~ShaderArchiveWriter() = default; std::optional InferShaderTypefromFileExtension( const std::filesystem::path& path) { +#if FML_OS_QNX + return std::nullopt; +#else // FML_OS_QNX if (path == ".vert") { return ArchiveShaderType::kVertex; } else if (path == ".frag") { @@ -26,9 +30,13 @@ std::optional InferShaderTypefromFileExtension( return ArchiveShaderType::kCompute; } return std::nullopt; +#endif // FML_OS_QNX } bool ShaderArchiveWriter::AddShaderAtPath(const std::string& std_path) { +#if FML_OS_QNX + return false; +#else // FML_OS_QNX std::filesystem::path path(std_path); if (path.stem().empty()) { @@ -69,6 +77,7 @@ bool ShaderArchiveWriter::AddShaderAtPath(const std::string& std_path) { } return AddShader(shader_type.value(), shader_name, std::move(file_mapping)); +#endif // FML_OS_QNX } bool ShaderArchiveWriter::AddShader(ArchiveShaderType type, diff --git a/engine/src/flutter/impeller/tessellator/tessellator.cc b/engine/src/flutter/impeller/tessellator/tessellator.cc index e4c68b6dcd358..51dbff8e68e08 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator.cc @@ -11,6 +11,7 @@ namespace { static constexpr int kPrecomputedDivisionCount = 1024; + static int kPrecomputedDivisions[kPrecomputedDivisionCount] = { // clang-format off 1, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, @@ -435,6 +436,7 @@ Tessellator::Trigs Tessellator::GetTrigsForDivisions(size_t divisions) { using TessellatedVertexProc = Tessellator::TessellatedVertexProc; using EllipticalVertexGenerator = Tessellator::EllipticalVertexGenerator; +using ArcVertexGenerator = Tessellator::ArcVertexGenerator; EllipticalVertexGenerator::EllipticalVertexGenerator( EllipticalVertexGenerator::GeneratorProc& generator, @@ -484,6 +486,106 @@ EllipticalVertexGenerator Tessellator::StrokedCircle( } } +ArcVertexGenerator::ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + bool use_center, + bool supports_triangle_fans) + : iteration_(iteration), + trigs_(std::move(trigs)), + oval_bounds_(oval_bounds), + use_center_(use_center), + half_width_(-1.0f), + cap_(Cap::kButt), + supports_triangle_fans_(supports_triangle_fans) {} + +ArcVertexGenerator::ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + Scalar half_width, + Cap cap) + : iteration_(iteration), + trigs_(std::move(trigs)), + oval_bounds_(oval_bounds), + use_center_(false), + half_width_(half_width), + cap_(cap), + supports_triangle_fans_(false) {} + +PrimitiveType ArcVertexGenerator::GetTriangleType() const { + return (half_width_ < 0 && supports_triangle_fans_) + ? PrimitiveType::kTriangleFan + : PrimitiveType::kTriangleStrip; +} + +size_t ArcVertexGenerator::GetVertexCount() const { + size_t count = iteration_.GetPointCount(); + if (half_width_ > 0) { + FML_DCHECK(!use_center_); + FML_DCHECK(cap_ != Cap::kRound); + count *= 2; + if (cap_ == Cap::kSquare) { + count += 4; + } + } else if (supports_triangle_fans_) { + if (use_center_) { + count++; + } + } else { + // corrugated triangle fan + count += (count + 1) / 2; + } + return count; +} + +void ArcVertexGenerator::GenerateVertices( + const TessellatedVertexProc& proc) const { + if (half_width_ > 0) { + FML_DCHECK(!use_center_); + Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_, + half_width_, cap_, proc); + } else if (supports_triangle_fans_) { + Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_, + use_center_, proc); + } else { + Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_, + use_center_, proc); + } +} + +ArcVertexGenerator Tessellator::FilledArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool use_center, + bool supports_triangle_fans) { + size_t divisions = + ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * + oval_bounds.GetSize().MaxDimension()); + + return ArcVertexGenerator( + ComputeArcQuadrantIterations(divisions + 1, start, sweep), + GetTrigsForDivisions(divisions), oval_bounds, use_center, + supports_triangle_fans); +}; + +ArcVertexGenerator Tessellator::StrokedArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + Cap cap, + Scalar half_width) { + FML_DCHECK(half_width > 0); + FML_DCHECK(oval_bounds.IsSquare()); + size_t divisions = ComputeQuadrantDivisions( + view_transform.GetMaxBasisLengthXY() * + (oval_bounds.GetSize().MaxDimension() + half_width)); + + return ArcVertexGenerator( + ComputeArcQuadrantIterations(divisions + 1, start, sweep), + GetTrigsForDivisions(divisions), oval_bounds, half_width, cap); +} + EllipticalVertexGenerator Tessellator::RoundCapLine( const Matrix& view_transform, const Point& p0, @@ -578,7 +680,7 @@ void Tessellator::GenerateFilledCircle( // we can instead iterate forward and swap the x/y values of the // offset as the angles should be symmetric and thus should generate // symmetrically reversed trig vectors. - // Quadrant 2 connecting with Quadrant 2: + // Quadrant 2 connecting with Quadrant 3: for (auto& trig : trigs) { auto offset = trig * radius; proc({center.x + offset.y, center.y + offset.x}); @@ -641,6 +743,98 @@ void Tessellator::GenerateStrokedCircle( } } +void Tessellator::GenerateFilledArcFan(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size radii = oval_bounds.GetSize() * 0.5f; + + if (use_center) { + proc(center); + } + proc(center + iteration.start * radii); + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + proc(center + trigs[j] * quadrant.axis * radii); + } + } + proc(center + iteration.end * radii); +} + +void Tessellator::GenerateFilledArcStrip(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size radii = oval_bounds.GetSize() * 0.5f; + + Point origin; + if (use_center) { + origin = center; + } else { + Point midpoint = (iteration.start + iteration.end) * 0.5f; + origin = center + midpoint * radii; + } + + proc(origin); + proc(center + iteration.start * radii); + bool insert_origin = false; + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + if (insert_origin) { + proc(origin); + } + insert_origin = !insert_origin; + proc(center + trigs[j] * quadrant.axis * radii); + } + } + if (insert_origin) { + proc(origin); + } + proc(center + iteration.end * radii); +} + +void Tessellator::GenerateStrokedArc(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + Scalar half_width, + Cap cap, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size base_radii = oval_bounds.GetSize() * 0.5f; + Size inner_radii = base_radii - Size(half_width, half_width); + Size outer_radii = base_radii + Size(half_width, half_width); + + FML_DCHECK(cap != Cap::kRound); + if (cap == Cap::kSquare) { + Vector2 offset = + Vector2{iteration.start.y, -iteration.start.x} * half_width; + proc(center + iteration.start * inner_radii + offset); + proc(center + iteration.start * outer_radii + offset); + } + proc(center + iteration.start * inner_radii); + proc(center + iteration.start * outer_radii); + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + proc(center + trigs[j] * quadrant.axis * inner_radii); + proc(center + trigs[j] * quadrant.axis * outer_radii); + } + } + proc(center + iteration.end * inner_radii); + proc(center + iteration.end * outer_radii); + if (cap == Cap::kSquare) { + Vector2 offset = Vector2{-iteration.end.y, iteration.end.x} * half_width; + proc(center + iteration.end * inner_radii + offset); + proc(center + iteration.end * outer_radii + offset); + } +} + void Tessellator::GenerateRoundCapLine( const Trigs& trigs, const EllipticalVertexGenerator::Data& data, @@ -734,4 +928,103 @@ void Tessellator::GenerateFilledRoundRect( } } +const Tessellator::ArcIteration Tessellator::ComputeCircleArcIterations( + size_t count) { + return { + {1.0f, 0.0f}, + {1.0f, 0.0f}, + 4u, + { + {kQuadrantAxes[0], 1u, count}, + {kQuadrantAxes[1], 0u, count}, + {kQuadrantAxes[2], 0u, count}, + {kQuadrantAxes[3], 0u, count}, + {{}, 0u, 0u}, + }, + }; +} + +Tessellator::ArcIteration Tessellator::ComputeArcQuadrantIterations( + size_t trig_size, + Degrees start, + Degrees sweep) { + if (sweep.degrees == 0 || !start.IsFinite() || !sweep.IsFinite()) { + return {}; + } + + if (sweep.degrees < 0) { + start = start + sweep; + sweep = -sweep; + } + + size_t steps = trig_size - 1; + + if (sweep.degrees >= 360) { + return ComputeCircleArcIterations(steps); + } + + start = start.GetPositive(); + Degrees end = start + sweep; + FML_DCHECK(start.degrees >= 0.0f && start.degrees < 360.0f); + FML_DCHECK(end >= start && end.degrees < start.degrees + 360.0f); + + ArcIteration iterations; + iterations.start = impeller::Matrix::CosSin(start); + iterations.end = impeller::Matrix::CosSin(end); + + // We nudge the start and stop by 1/10th of a step so we don't end + // up with degenerately small steps at the start and end of the + // arc. + Degrees nudge = Degrees((90.0f / steps) * 0.1f); + + if ((start + nudge) >= (end - nudge)) { + iterations.quadrant_count = 0u; + return iterations; + } + + int cur_quadrant = + static_cast(std::floor((start + nudge).degrees / 90.0f)); + int end_quadrant = + static_cast(std::floor((end - nudge).degrees / 90.0f)); + FML_DCHECK(cur_quadrant >= 0 && // + cur_quadrant <= 4); + FML_DCHECK(end_quadrant >= cur_quadrant && // + end_quadrant <= cur_quadrant + 4); + FML_DCHECK(cur_quadrant * 90 <= (start + nudge).degrees); + FML_DCHECK(end_quadrant * 90 + 90 >= (end - nudge).degrees); + + auto next_step = [steps](Degrees angle, int quadrant) -> size_t { + Scalar quadrant_fract = angle.degrees / 90.0f - quadrant; + return static_cast(std::ceil(quadrant_fract * steps)); + }; + + int i = 0; + iterations.quadrants[i] = { + kQuadrantAxes[cur_quadrant & 3], + next_step(start + nudge, cur_quadrant), + steps, + }; + if (iterations.quadrants[0].end_index > iterations.quadrants[0].start_index) { + i++; + } + while (cur_quadrant < end_quadrant) { + iterations.quadrants[i++] = { + kQuadrantAxes[(++cur_quadrant) % 4], + 0u, + steps, + }; + } + FML_DCHECK(i <= 5); + if (i > 0) { + iterations.quadrants[i - 1].end_index = + next_step(end - nudge, cur_quadrant); + if (iterations.quadrants[i - 1].end_index <= + iterations.quadrants[i - 1].start_index) { + i--; + } + } + iterations.quadrant_count = i; + return iterations; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/tessellator/tessellator.h b/engine/src/flutter/impeller/tessellator/tessellator.h index 6cf408d6e8c14..fe72e692de1ad 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.h +++ b/engine/src/flutter/impeller/tessellator/tessellator.h @@ -14,11 +14,13 @@ #include "impeller/core/vertex_buffer.h" #include "impeller/geometry/path_source.h" #include "impeller/geometry/point.h" +#include "impeller/geometry/stroke_parameters.h" #include "impeller/geometry/trig.h" namespace impeller { /// The size of the point arena buffer stored on the tessellator. +[[maybe_unused]] static constexpr size_t kPointArenaSize = 4096u; //------------------------------------------------------------------------------ @@ -181,6 +183,116 @@ class Tessellator { Data&& data); }; + /// A structure to describe the iteration through a set of angle vectors + /// in a |Trigs| structure to render the points along an arc. The start + /// and end vectors and each iteration's axis vector are all unit vectors + /// that point in the direction of the point on the circle to be emitted. + /// + /// Each vector should be rendered by multiplying it by the radius of the + /// circle, or in the case of a stroked arc, by the inner and outer radii + /// of the sides of the stroke. + /// + /// - The start vector will always be rendered first. + /// - Then each quadrant will be iterated by composing the trigs vectors + /// with the given axis vector, iterating from the start index (inclusive) + /// to the end index (exclusive) of the vector of |Trig| values. + /// - Finally the end vector will be rendered. + /// For example: + /// Insert(arc_iteration.start * radius); + /// for (size_t i = 0u, i < arc_iteration.iteration_count; i++) { + /// Quadrant quadrant = arc_iteration.quadrants[i]; + /// for (j = quadrant.start_index; j < quadrant.end_index; j++) { + /// Insert(quadrant.axis * trigs[j] * radius); + /// } + /// } + /// Insert(arc_iteration.end * radius); + /// + /// The rendering routine may adjust the manner/order in which those vertices + /// are inserted into the vertex buffer to optimally match the vertex triangle + /// mode it plans to use, but the description above represents the basic + /// technique to compute the points along the actual curve. + struct ArcIteration { + // The axis to multiply by each |Trig| value and the half-open [start, end) + // range of the |Trig| vector over which to compute. + struct Quadrant { + impeller::Vector2 axis; + size_t start_index = 0u; + size_t end_index = 0u; + + size_t GetPointCount() const { + FML_DCHECK(start_index < end_index); + return end_index - start_index; + } + }; + + // The true begin and end angles of the arc, expressed as unit direction + // vectors. + impeller::Vector2 start; + impeller::Vector2 end; + + // The variable number of quadrants that have to be iterated and + // cross-referenced with values in a |Trigs| object. + size_t quadrant_count = 0u; + // We can have at most 5 |Quadrant| entries when an arc starts and ends in + // the same circle quadrant with the start point later in the quadrant + // than the end point. + // + // Worst case: + // - First iteration goes from the start angle to the end of that quadrant. + // - Then 3 full iterations for the 3 other full quarter circles. + // - Then a last iteration that goes from the start of that quadrant to the + // end angle. + // + // We can also have 0 quadrants for arcs that are smaller than the + // step size of the pixel-radius |Trigs| vector. + Quadrant quadrants[5]; + + size_t GetPointCount() const { + size_t count = 2; + for (size_t i = 0; i < quadrant_count; i++) { + count += quadrants[i].GetPointCount(); + } + return count; + } + }; + + /// @brief The |VertexGenerator| implementation common to all shapes + /// that are based on a polygonal representation of an ellipse. + class ArcVertexGenerator : public virtual VertexGenerator { + public: + /// |VertexGenerator| + PrimitiveType GetTriangleType() const override; + + /// |VertexGenerator| + size_t GetVertexCount() const override; + + /// |VertexGenerator| + void GenerateVertices(const TessellatedVertexProc& proc) const override; + + private: + friend class Tessellator; + + const ArcIteration iteration_; + const Trigs trigs_; + const Rect oval_bounds_; + const bool use_center_; + const Scalar half_width_; + const Cap cap_; + const bool supports_triangle_fans_; + + ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + bool use_center, + bool supports_triangle_fans); + + ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + Scalar half_width, + Cap cap); + }; + Tessellator(); virtual ~Tessellator(); @@ -250,6 +362,44 @@ class Tessellator { Scalar radius, Scalar half_width); + /// @brief Create a |VertexGenerator| that can produce vertices for + /// a stroked arc inscribed within the given oval_bounds with + /// the given stroke half_width with enough polygon sub-divisions + /// to provide reasonable fidelity when viewed under the given + /// view transform. The outer edge of the stroked arc is + /// generated at (radius + half_width) and the inner edge is + /// generated at (radius - half_width). + /// + /// Note that the view transform is only used to choose the + /// number of sample points to use per quarter circle and the + /// returned points are not transformed by it, instead they are + /// relative to the coordinate space of the oval bounds. + ArcVertexGenerator FilledArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool use_center, + bool supports_triangle_fans); + + /// @brief Create a |VertexGenerator| that can produce vertices for + /// a stroked arc inscribed within the given oval_bounds with + /// the given stroke half_width with enough polygon sub-divisions + /// to provide reasonable fidelity when viewed under the given + /// view transform. The outer edge of the stroked arc is + /// generated at (radius + half_width) and the inner edge is + /// generated at (radius - half_width). + /// + /// Note that the view transform is only used to choose the + /// number of sample points to use per quarter circle and the + /// returned points are not transformed by it, instead they are + /// relative to the coordinate space of the oval bounds. + ArcVertexGenerator StrokedArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + Cap cap, + Scalar half_width); + /// @brief Create a |VertexGenerator| that can produce vertices for /// a line with round end caps of the given radius with enough /// polygon sub-divisions to provide reasonable fidelity when @@ -296,6 +446,10 @@ class Tessellator { /// circle quadrant of the specified pixel radius Trigs GetTrigsForDeviceRadius(Scalar pixel_radius); + static ArcIteration ComputeArcQuadrantIterations(size_t trig_count, + impeller::Degrees start, + impeller::Degrees sweep); + protected: /// Used for polyline generation. std::unique_ptr> point_buffer_; @@ -320,6 +474,25 @@ class Tessellator { const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); + static void GenerateFilledArcFan(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc); + + static void GenerateFilledArcStrip(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc); + + static void GenerateStrokedArc(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + Scalar half_width, + Cap cap, + const TessellatedVertexProc& proc); + static void GenerateRoundCapLine(const Trigs& trigs, const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); @@ -333,6 +506,8 @@ class Tessellator { const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); + static const ArcIteration ComputeCircleArcIterations(size_t count); + Tessellator(const Tessellator&) = delete; Tessellator& operator=(const Tessellator&) = delete; diff --git a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc index 9ebd50d550d0b..159e839a0d8d5 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc @@ -526,5 +526,268 @@ TEST(TessellatorTest, EarlyReturnEmptyConvexShape) { EXPECT_TRUE(indices.empty()); } +namespace { + +// Tests the basic relationships of the angles iterated according to the +// rules of the ArcIteration struct. Each step iterated should be just +// about the same angular distance from the previous step, computed using +// the Cross product of the adjacent vectors, which should be the same as +// the sine of the angle between them when using unit vectors. +// +// Special support for shorter starting and ending steps to bridge the gap +// from the true arc start and the true arc end and the first and last +// angles iterated from the trigs. +void TestArcIterator(const impeller::Tessellator::ArcIteration arc_iteration, + const impeller::Tessellator::Trigs& trigs, + Degrees start, + Degrees sweep, + const std::string& label) { + EXPECT_POINT_NEAR(arc_iteration.start, impeller::Matrix::CosSin(start)) + << label; + EXPECT_POINT_NEAR(arc_iteration.end, impeller::Matrix::CosSin(start + sweep)) + << label; + if (arc_iteration.quadrant_count == 0u) { + // There is just the begin and end angle and there are no constraints + // on how far apart they should be, but the end vector should be + // non-counterclockwise from the start vector. + EXPECT_GE(arc_iteration.start.Cross(arc_iteration.end), 0.0f); + return; + } + + const size_t steps = trigs.size() - 1; + const Scalar step_angle = kPiOver2 / steps; + + // The first and last steps are allowed to be from 0.1 to 1.1 in size + // as we don't want to iterate an extra step that is less than 0.1 steps + // from the begin/end angles. We use min/max values that are ever so + // slightly larger than that to avoid round-off errors. + const Scalar edge_min_cross = std::sin(step_angle * 0.099f); + const Scalar edge_max_cross = std::sin(step_angle * 1.101f); + const Scalar typical_min_cross = std::sin(step_angle * 0.999f); + const Scalar typical_max_cross = std::sin(step_angle * 1.001f); + + Vector2 cur_vector; + auto trace = [&cur_vector](Vector2 vector, Scalar min_cross, Scalar max_cross, + const std::string& label) -> void { + EXPECT_GT(cur_vector.Cross(vector), min_cross) << label; + EXPECT_LT(cur_vector.Cross(vector), max_cross) << label; + cur_vector = vector; + }; + + // The first edge encountered in the loop should be judged by the edge + // conditions. After that the steps derived from the Trigs should be + // judged by the typical min/max values. + Scalar min_cross = edge_min_cross; + Scalar max_cross = edge_max_cross; + + cur_vector = arc_iteration.start; + for (size_t i = 0; i < arc_iteration.quadrant_count; i++) { + auto& quadrant = arc_iteration.quadrants[i]; + EXPECT_LT(quadrant.start_index, quadrant.end_index) + << label << ", quadrant: " << i; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + trace(trigs[j] * quadrant.axis, min_cross, max_cross, + label + ", quadrant: " + std::to_string(i) + + ", step: " + std::to_string(j)); + // At this point we can guarantee that we've already used the initial + // min/max values, now replace them with the typical values. + min_cross = typical_min_cross; + max_cross = typical_max_cross; + } + } + + // The jump to the end angle should be judged by the edge conditions. + trace(arc_iteration.end, edge_min_cross, edge_max_cross, + label + " step to end"); +} + +void TestFullCircleArc(Degrees start, Degrees sweep) { + auto label = + std::to_string(start.degrees) + " += " + std::to_string(sweep.degrees); + + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + size_t steps = trigs.size() - 1; + const auto& arc_iteration = + impeller::Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, + sweep); + + EXPECT_EQ(arc_iteration.start, Vector2(1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrant_count, 4u) << label; + EXPECT_EQ(arc_iteration.quadrants[0].axis, Vector2(1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[0].start_index, 1u) << label; + EXPECT_EQ(arc_iteration.quadrants[0].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[1].axis, Vector2(0.0f, 1.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[1].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[1].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[2].axis, Vector2(-1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[2].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[2].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[3].axis, Vector2(0.0f, -1.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[3].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[3].end_index, steps) << label; + EXPECT_EQ(arc_iteration.end, Vector2(1.0f, 0.0f)) << label; + + // For full circle arcs the original start and sweep are ignored and it + // returns an iterator that always goes from 0->360. + TestArcIterator(arc_iteration, trigs, Degrees(0), Degrees(360), + "Full Circle(" + label + ")"); +} + +} // namespace + +TEST(TessellatorTest, ArcIterationsFullCircle) { + // Anything with a sweep <=-360 or >=360 is a full circle regardless of + // starting angle + for (int start = -720; start < 720; start += 30) { + for (int sweep = 360; sweep < 1080; sweep += 45) { + TestFullCircleArc(Degrees(start), Degrees(sweep)); + TestFullCircleArc(Degrees(start), Degrees(-sweep)); + } + } +} + +namespace { +static void CheckOneQuadrant(Degrees start, Degrees sweep) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + EXPECT_POINT_NEAR(arc_iteration.start, Matrix::CosSin(start)); + EXPECT_EQ(arc_iteration.quadrant_count, 1u); + EXPECT_POINT_NEAR(arc_iteration.end, Matrix::CosSin(start + sweep)); + + std::string label = "Quadrant(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees) + ")"; + TestArcIterator(arc_iteration, trigs, start, sweep, label); +} +} // namespace + +TEST(TessellatorTest, ArcIterationsVariousStartAnglesNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const Degrees sweep(45); + + for (int start_i = -1000; start_i < 1000; start_i += 5) { + Scalar start_degrees = start_i * 0.01f; + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + start_degrees); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsVariousEndAnglesNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + + for (int sweep_i = 5; sweep_i < 20000; sweep_i += 5) { + const Degrees sweep(sweep_i * 0.01f); + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + 80); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsVariousTinyArcsNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const Degrees sweep(0.1f); + + for (int start_i = -1000; start_i < 1000; start_i += 5) { + Scalar start_degrees = start_i * 0.01f; + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + start_degrees); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + ASSERT_EQ(arc_iteration.quadrant_count, 0u); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsOnlyFirstQuadrant) { + CheckOneQuadrant(Degrees(90 * 0 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlySecondQuadrant) { + CheckOneQuadrant(Degrees(90 * 1 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlyThirdQuadrant) { + CheckOneQuadrant(Degrees(90 * 2 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlyFourthQuadrant) { + CheckOneQuadrant(Degrees(90 * 3 + 30), Degrees(30)); +} + +namespace { +static void CheckFiveQuadrants(Degrees start, Degrees sweep) { + std::string label = + std::to_string(start.degrees) + " += " + std::to_string(sweep.degrees); + + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + size_t steps = trigs.size() - 1; + + EXPECT_POINT_NEAR(arc_iteration.start, Matrix::CosSin(start)) << label; + EXPECT_EQ(arc_iteration.quadrant_count, 5u) << label; + + // quadrant 0 start index depends on angle + EXPECT_EQ(arc_iteration.quadrants[0].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[1].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[1].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[2].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[2].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[3].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[3].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[4].start_index, 0u) << label; + // quadrant 4 end index depends on angle + + EXPECT_POINT_NEAR(arc_iteration.end, Matrix::CosSin(start + sweep)) << label; + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Five quadrants(" + label + ")"); +} +} // namespace + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromFirst) { + CheckFiveQuadrants(Degrees(90 * 0 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromSecond) { + CheckFiveQuadrants(Degrees(90 * 1 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromThird) { + CheckFiveQuadrants(Degrees(90 * 2 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromFourth) { + CheckFiveQuadrants(Degrees(90 * 3 + 60), Degrees(330)); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/toolkit/interop/BUILD.gn b/engine/src/flutter/impeller/toolkit/interop/BUILD.gn index 19622807ed94f..001d05f01fde0 100644 --- a/engine/src/flutter/impeller/toolkit/interop/BUILD.gn +++ b/engine/src/flutter/impeller/toolkit/interop/BUILD.gn @@ -219,7 +219,7 @@ zip_bundle("sdk") { destination = "lib/libimpeller.dylib" }, ] - } else if (is_linux || is_android) { + } else if (is_linux || is_android || is_qnx) { files += [ { source = "$root_build_dir/libimpeller.so" diff --git a/engine/src/flutter/impeller/toolkit/interop/formats.h b/engine/src/flutter/impeller/toolkit/interop/formats.h index 8ffd82ee4bac4..9fd55ba77e585 100644 --- a/engine/src/flutter/impeller/toolkit/interop/formats.h +++ b/engine/src/flutter/impeller/toolkit/interop/formats.h @@ -94,7 +94,7 @@ constexpr flutter::DlColor ToDisplayListType(Color color) { ); } -constexpr SkMatrix ToSkMatrix(const Matrix& matrix) { +inline SkMatrix ToSkMatrix(const Matrix& matrix) { return SkM44::ColMajor(matrix.m).asM33(); } diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.cc b/engine/src/flutter/impeller/toolkit/interop/impeller.cc index 3c75dd0b3fbb9..ea54089bee0b5 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.cc @@ -1159,6 +1159,12 @@ void ImpellerParagraphStyleSetLocale(ImpellerParagraphStyle paragraph_style, GetPeer(paragraph_style)->SetLocale(ReadString(locale)); } +IMPELLER_EXTERN_C +void ImpellerParagraphStyleSetEllipsis(ImpellerParagraphStyle paragraph_style, + const char* ellipsis) { + GetPeer(paragraph_style)->SetEllipsis(ReadString(ellipsis)); +} + IMPELLER_EXTERN_C void ImpellerDisplayListBuilderDrawParagraph(ImpellerDisplayListBuilder builder, ImpellerParagraph paragraph, diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.h b/engine/src/flutter/impeller/toolkit/interop/impeller.h index 4353fc599a82b..78f47645ae2a0 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.h +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.h @@ -2472,6 +2472,18 @@ void ImpellerParagraphStyleSetLocale( ImpellerParagraphStyle IMPELLER_NONNULL paragraph_style, const char* IMPELLER_NONNULL locale); +//------------------------------------------------------------------------------ +/// @brief Set the UTF-8 string to use as the ellipsis. Pass `nullptr` to +/// clear the setting to default. +/// +/// @param[in] paragraph_style The paragraph style. +/// @param[in] data The ellipsis string UTF-8 data, or null. +/// +IMPELLER_EXPORT +void ImpellerParagraphStyleSetEllipsis( + ImpellerParagraphStyle IMPELLER_NONNULL paragraph_style, + const char* IMPELLER_NULLABLE ellipsis); + //------------------------------------------------------------------------------ // Paragraph Builder //------------------------------------------------------------------------------ diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp index a5dd4cc40d456..10418b4520096 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp @@ -168,6 +168,7 @@ struct Proc { PROC(ImpellerParagraphStyleRelease) \ PROC(ImpellerParagraphStyleRetain) \ PROC(ImpellerParagraphStyleSetBackground) \ + PROC(ImpellerParagraphStyleSetEllipsis) \ PROC(ImpellerParagraphStyleSetFontFamily) \ PROC(ImpellerParagraphStyleSetFontSize) \ PROC(ImpellerParagraphStyleSetFontStyle) \ @@ -232,7 +233,7 @@ struct ProcTable { return true; } -#define IMPELLER_HPP_PROC(name) Proc name = {#name, nullptr}; +#define IMPELLER_HPP_PROC(name) Proc name = {#name}; IMPELLER_HPP_EACH_PROC(IMPELLER_HPP_PROC) #undef IMPELLER_HPP_PROC }; @@ -1088,6 +1089,14 @@ class ParagraphStyle return *this; } + //---------------------------------------------------------------------------- + /// @see ImpellerParagraphStyleSetEllipsis + /// + ParagraphStyle& SetEllipsis(const char* ellipsis) { + gGlobalProcTable.ImpellerParagraphStyleSetEllipsis(Get(), ellipsis); + return *this; + } + //---------------------------------------------------------------------------- /// @see ImpellerParagraphStyleSetMaxLines /// diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc index 8e36a18f4994c..48812e71385b9 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc @@ -631,4 +631,29 @@ TEST_P(InteropPlaygroundTest, CanGetPathBounds) { ASSERT_EQ(bounds.height, 100); } +TEST_P(InteropPlaygroundTest, CanControlEllipses) { + hpp::TypographyContext context; + auto style = hpp::ParagraphStyle{}; + style.SetFontSize(50); + style.SetForeground(hpp::Paint{}.SetColor({.red = 1.0, .alpha = 1.0})); + const auto text = std::string{"The quick brown fox jumped over the lazy dog"}; + style.SetEllipsis("🐶"); + auto para1 = + hpp::ParagraphBuilder{context}.PushStyle(style).AddText(text).Build(250); + style.SetForeground(hpp::Paint{}.SetColor({.green = 1.0, .alpha = 1.0})); + style.SetEllipsis(nullptr); + auto para2 = + hpp::ParagraphBuilder{context}.PushStyle(style).AddText(text).Build(250); + auto dl = hpp::DisplayListBuilder{} + .DrawParagraph(para1, {100, 100}) + .DrawParagraph(para2, {100, 200}) + .Build(); + ASSERT_TRUE( + OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool { + hpp::Surface window(surface.GetC()); + window.Draw(dl); + return true; + })); +} + } // namespace impeller::interop::testing diff --git a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc index 25982bf27c5ca..780d6e03fc93c 100644 --- a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc +++ b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc @@ -4,6 +4,8 @@ #include "impeller/toolkit/interop/paragraph_style.h" +#include "flutter/fml/string_conversion.h" + namespace impeller::interop { ParagraphStyle::ParagraphStyle() = default; @@ -84,4 +86,12 @@ void ParagraphStyle::SetTextDecoration( decoration_ = decoration; } +void ParagraphStyle::SetEllipsis(const std::string& string) { + if (string.empty()) { + style_.ellipsis = {}; + return; + } + style_.ellipsis = fml::Utf8ToUtf16(string); +} + } // namespace impeller::interop diff --git a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h index 26e33d1855862..d3bab1f060253 100644 --- a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h +++ b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h @@ -48,6 +48,8 @@ class ParagraphStyle final void SetLocale(std::string locale); + void SetEllipsis(const std::string& string); + txt::TextStyle CreateTextStyle() const; const txt::ParagraphStyle& GetParagraphStyle() const; diff --git a/engine/src/flutter/impeller/tools/args.gni b/engine/src/flutter/impeller/tools/args.gni index adfc111ffce15..543fc38382572 100644 --- a/engine/src/flutter/impeller/tools/args.gni +++ b/engine/src/flutter/impeller/tools/args.gni @@ -13,12 +13,14 @@ declare_args() { impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia" # Whether the OpenGLES backend is enabled. - impeller_enable_opengles = (is_linux || is_win || is_android || is_mac || - enable_unittests) && target_os != "fuchsia" + impeller_enable_opengles = + (is_linux || is_win || is_android || is_mac || is_qnx || + enable_unittests) && target_os != "fuchsia" # Whether the Vulkan backend is enabled. - impeller_enable_vulkan = (is_linux || is_win || is_android || is_mac || - enable_unittests) && target_os != "fuchsia" + impeller_enable_vulkan = + (is_linux || is_win || is_android || is_mac || is_qnx || + enable_unittests) && target_os != "fuchsia" } # Arguments that are combinations of other arguments by default but which can diff --git a/engine/src/flutter/impeller/tools/component.gni b/engine/src/flutter/impeller/tools/component.gni index d6fdef6b5e914..3ffd94b7f76dd 100644 --- a/engine/src/flutter/impeller/tools/component.gni +++ b/engine/src/flutter/impeller/tools/component.gni @@ -36,8 +36,9 @@ template("impeller_component") { if (!defined(invoker.cflags)) { cflags = [] } - cflags += [ "-Wthread-safety-analysis" ] - + if (is_clang) { + cflags += [ "-Wthread-safety-analysis" ] + } if (!defined(invoker.cflags_objc)) { cflags_objc = [] } diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json index c4b266e34a034..3d518ec7367cd 100644 --- a/engine/src/flutter/impeller/tools/malioc.json +++ b/engine/src/flutter/impeller/tools/malioc.json @@ -5161,16 +5161,16 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 71, + "fp16_arithmetic": 60, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "varying" ], "longest_path_cycles": [ - 0.21875, - 0.21875, - 0.03125, + 0.28125, + 0.28125, + 0.078125, 0.0, 0.0, 0.5, @@ -5189,9 +5189,9 @@ "varying" ], "shortest_path_cycles": [ - 0.21875, - 0.21875, - 0.0, + 0.28125, + 0.28125, + 0.046875, 0.0, 0.0, 0.5, @@ -5201,9 +5201,9 @@ "varying" ], "total_cycles": [ - 0.21875, - 0.21875, - 0.03125, + 0.28125, + 0.28125, + 0.078125, 0.0, 0.0, 0.5, @@ -5212,7 +5212,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 4, + "uniform_registers_used": 6, "work_registers_used": 20 } } @@ -5230,7 +5230,7 @@ "arithmetic" ], "longest_path_cycles": [ - 1.3200000524520874, + 2.309999942779541, 1.0, 1.0 ], @@ -5243,7 +5243,7 @@ "arithmetic" ], "shortest_path_cycles": [ - 1.3200000524520874, + 2.309999942779541, 1.0, 1.0 ], @@ -5251,7 +5251,7 @@ "arithmetic" ], "total_cycles": [ - 1.6666666269302368, + 2.6666667461395264, 1.0, 1.0 ] @@ -9014,16 +9014,16 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 100, + "fp16_arithmetic": 60, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "varying" ], "longest_path_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9042,9 +9042,9 @@ "varying" ], "shortest_path_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9054,9 +9054,9 @@ "varying" ], "total_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9065,8 +9065,8 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 6, - "work_registers_used": 8 + "uniform_registers_used": 10, + "work_registers_used": 9 } } } diff --git a/engine/src/flutter/impeller/typographer/font_glyph_pair.h b/engine/src/flutter/impeller/typographer/font_glyph_pair.h index d5757c34a5897..f8fcc68292708 100644 --- a/engine/src/flutter/impeller/typographer/font_glyph_pair.h +++ b/engine/src/flutter/impeller/typographer/font_glyph_pair.h @@ -21,8 +21,8 @@ struct GlyphProperties { std::optional stroke; struct Equal { - constexpr bool operator()(const impeller::GlyphProperties& lhs, - const impeller::GlyphProperties& rhs) const { + inline bool operator()(const impeller::GlyphProperties& lhs, + const impeller::GlyphProperties& rhs) const { return lhs.color.ToARGB() == rhs.color.ToARGB() && lhs.stroke == rhs.stroke; } @@ -43,8 +43,8 @@ struct ScaledFont { } struct Equal { - constexpr bool operator()(const impeller::ScaledFont& lhs, - const impeller::ScaledFont& rhs) const { + inline bool operator()(const impeller::ScaledFont& lhs, + const impeller::ScaledFont& rhs) const { return lhs.font.IsEqual(rhs.font) && lhs.scale == rhs.scale; } }; diff --git a/engine/src/flutter/lib/ui/dart_ui.cc b/engine/src/flutter/lib/ui/dart_ui.cc index d0318ddb28f85..51d7a6c46a20a 100644 --- a/engine/src/flutter/lib/ui/dart_ui.cc +++ b/engine/src/flutter/lib/ui/dart_ui.cc @@ -84,6 +84,7 @@ typedef CanvasPath Path; /* Other */ \ V(FontCollection::LoadFontFromList) \ V(ImageDescriptor::initEncoded) \ + V(ImageFilter::equals) \ V(ImmutableBuffer::init) \ V(ImmutableBuffer::initFromAsset) \ V(ImmutableBuffer::initFromFile) \ @@ -209,7 +210,6 @@ typedef CanvasPath Path; V(ImageFilter, initComposeFilter) \ V(ImageFilter, initShader) \ V(ImageFilter, initMatrix) \ - V(ImageFilter, equals) \ V(ImageShader, dispose) \ V(ImageShader, initWithImage) \ V(ImmutableBuffer, dispose) \ diff --git a/engine/src/flutter/lib/ui/fixtures/ui_test.dart b/engine/src/flutter/lib/ui/fixtures/ui_test.dart index fc920d608e7b0..0b3273db91d09 100644 --- a/engine/src/flutter/lib/ui/fixtures/ui_test.dart +++ b/engine/src/flutter/lib/ui/fixtures/ui_test.dart @@ -213,8 +213,6 @@ void sendSemanticsUpdate() { scrollExtentMax: 0, scrollExtentMin: 0, rect: Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: identifier, label: label, labelAttributes: labelAttributes, @@ -267,8 +265,6 @@ void sendSemanticsUpdateWithRole() { scrollExtentMax: 0, scrollExtentMin: 0, rect: Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: "identifier", label: "label", labelAttributes: const [], diff --git a/engine/src/flutter/lib/ui/painting.dart b/engine/src/flutter/lib/ui/painting.dart index 4390a0c8d75d0..6a9af0cc80f74 100644 --- a/engine/src/flutter/lib/ui/painting.dart +++ b/engine/src/flutter/lib/ui/painting.dart @@ -4242,6 +4242,10 @@ abstract class ImageFilter { /// also be at least one sampler2D uniform, the first of which will be set by /// the engine to contain the filter input. /// + /// When Impeller uses the OpenGL(ES) backend, the y-axis direction is + /// reversed. Custom fragment shaders must invert the y-axis on + /// GLES or they will render upside-down. + /// /// For example, the following is a valid fragment shader that can be used /// with this API. Note that the uniform names are not required to have any /// particular value. @@ -4257,7 +4261,12 @@ abstract class ImageFilter { /// out vec4 frag_color; /// /// void main() { - /// frag_color = texture(u_texture_input, FlutterFragCoord().xy / u_size) * u_time; + /// vec2 uv = FlutterFragCoord().xy / u_size; + /// // Reverse y axis for OpenGL backend. + /// #ifdef IMPELLER_TARGET_OPENGLES + /// uv.y = 1.0 - uv.y + /// #endif + /// frag_color = texture(u_texture_input, uv) * u_time; /// /// } /// @@ -4492,7 +4501,7 @@ class _FragmentShaderImageFilter implements ImageFilter { _equals(nativeFilter, other.nativeFilter); } - @Native(symbol: 'ImageFilter::equal') + @Native(symbol: 'ImageFilter::equals') external static bool _equals(_ImageFilter a, _ImageFilter b); @override diff --git a/engine/src/flutter/lib/ui/painting/image_filter.h b/engine/src/flutter/lib/ui/painting/image_filter.h index c251d9653f6f1..72997a1a18c89 100644 --- a/engine/src/flutter/lib/ui/painting/image_filter.h +++ b/engine/src/flutter/lib/ui/painting/image_filter.h @@ -36,7 +36,7 @@ class ImageFilter : public RefCountedDartWrappable { void initColorFilter(ColorFilter* colorFilter); void initComposeFilter(ImageFilter* outer, ImageFilter* inner); void initShader(ReusableFragmentShader* shader); - bool equals(ImageFilter* a, ImageFilter* b); + static bool equals(ImageFilter* a, ImageFilter* b); const std::shared_ptr filter(DlTileMode mode) const; diff --git a/engine/src/flutter/lib/ui/semantics.dart b/engine/src/flutter/lib/ui/semantics.dart index eeb6d9037721f..e137003903319 100644 --- a/engine/src/flutter/lib/ui/semantics.dart +++ b/engine/src/flutter/lib/ui/semantics.dart @@ -1633,14 +1633,6 @@ abstract class SemanticsUpdateBuilder { /// The `transform` is a matrix that maps this node's coordinate system into /// its parent's coordinate system. /// - /// The `elevation` describes the distance in z-direction between this node - /// and the `elevation` of the parent. - /// - /// The `thickness` describes how much space this node occupies in the - /// z-direction starting at `elevation`. Basically, in the z-direction the - /// node starts at `elevation` above the parent and ends at `elevation` + - /// `thickness` above the parent. - /// /// The `headingLevel` describes that this node is a heading and the hierarchy /// level this node represents as a heading. A value of 0 indicates that this /// node is not a heading. A value of 1 or greater indicates that this node is @@ -1680,8 +1672,6 @@ abstract class SemanticsUpdateBuilder { required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -1759,8 +1749,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -1809,8 +1797,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 rect.top, rect.right, rect.bottom, - elevation, - thickness, identifier, label, labelAttributes, @@ -1857,8 +1843,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 Double, Double, Double, - Double, - Double, Handle, Handle, Handle, @@ -1902,8 +1886,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 double top, double right, double bottom, - double elevation, - double thickness, String? identifier, String label, List labelAttributes, diff --git a/engine/src/flutter/lib/ui/semantics/semantics_node.h b/engine/src/flutter/lib/ui/semantics/semantics_node.h index f1f410cbb0c97..b4454eafbd749 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_node.h +++ b/engine/src/flutter/lib/ui/semantics/semantics_node.h @@ -170,8 +170,6 @@ struct SemanticsNode { double scrollPosition = std::nan(""); double scrollExtentMax = std::nan(""); double scrollExtentMin = std::nan(""); - double elevation = 0.0; - double thickness = 0.0; std::string identifier; std::string label; StringAttributes labelAttributes; diff --git a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc index f7bb621ed2175..8e4ba6884f8fc 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc +++ b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc @@ -74,8 +74,6 @@ void SemanticsUpdateBuilder::updateNode( double top, double right, double bottom, - double elevation, - double thickness, std::string identifier, std::string label, const std::vector& labelAttributes, @@ -118,8 +116,6 @@ void SemanticsUpdateBuilder::updateNode( node.scrollExtentMin = scrollExtentMin; node.rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)); - node.elevation = elevation; - node.thickness = thickness; node.identifier = std::move(identifier); node.label = std::move(label); pushStringAttributes(node.labelAttributes, labelAttributes); diff --git a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h index 88139bcdcde3c..bbb3c3fb3c4a5 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h +++ b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h @@ -47,8 +47,6 @@ class SemanticsUpdateBuilder double top, double right, double bottom, - double elevation, - double thickness, std::string identifier, std::string label, const std::vector& labelAttributes, diff --git a/engine/src/flutter/lib/ui/window.dart b/engine/src/flutter/lib/ui/window.dart index 48a18692cf85f..3db2091b15d3d 100644 --- a/engine/src/flutter/lib/ui/window.dart +++ b/engine/src/flutter/lib/ui/window.dart @@ -931,6 +931,7 @@ class AccessibilityFeatures { static const int _kReduceMotionIndex = 1 << 4; static const int _kHighContrastIndex = 1 << 5; static const int _kOnOffSwitchLabelsIndex = 1 << 6; + static const int _kNoAnnounceIndex = 1 << 7; // A bitfield which represents each enabled feature. final int _index; @@ -968,6 +969,20 @@ class AccessibilityFeatures { /// Only supported on iOS. bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0; + /// Whether accessibility announcements (like [SemanticsService.announce]) + /// are supported on the current platform. + /// + /// Returns `false` on platforms where announcements are deprecated or + /// unsupported by the underlying platform. + /// + /// Returns `true` on platforms where such announcements are + /// generally supported without discouragement. (iOS, web etc) + /// + /// Use this flag to conditionally avoid making announcements on Android. + // This index check is inverted (== 0 vs != 0); far more platforms support + // "announce" than discourage it. + bool get announce => _kNoAnnounceIndex & _index == 0; + @override String toString() { final List features = []; @@ -992,6 +1007,9 @@ class AccessibilityFeatures { if (onOffSwitchLabels) { features.add('onOffSwitchLabels'); } + if (announce) { + features.add('announce'); + } return 'AccessibilityFeatures$features'; } diff --git a/engine/src/flutter/lib/ui/window/platform_configuration.h b/engine/src/flutter/lib/ui/window/platform_configuration.h index 29ee8ca4fffaa..36e5ddac1ffca 100644 --- a/engine/src/flutter/lib/ui/window/platform_configuration.h +++ b/engine/src/flutter/lib/ui/window/platform_configuration.h @@ -48,6 +48,7 @@ enum class AccessibilityFeatureFlag : int32_t { kReduceMotion = 1 << 4, kHighContrast = 1 << 5, kOnOffSwitchLabels = 1 << 6, + kNoAnnounce = 1 << 7, }; //-------------------------------------------------------------------------- diff --git a/engine/src/flutter/lib/web_ui/README.md b/engine/src/flutter/lib/web_ui/README.md index 5248177cbf49c..5739b5300ebfb 100644 --- a/engine/src/flutter/lib/web_ui/README.md +++ b/engine/src/flutter/lib/web_ui/README.md @@ -27,7 +27,7 @@ The `build` subcommand builds web engine gn/ninja targets. Targets can be individually specified in the command line invocation, or if none are specified, all web engine targets are built. Common targets are as follows: * `sdk` - The flutter_web_sdk itself. - * `canvaskit` - Flutter's version of canvakit. + * `canvaskit` - Flutter's version of canvaskit. * `canvaskit_chromium` - A version of canvaskit optimized for use with chromium-based browsers. * `skwasm` - Builds experimental skia wasm module renderer. @@ -77,7 +77,7 @@ Several other flags can be passed that filter which test suites should be run: * `--compiler` runs only the test suites that use a particular compiler. Valid values for this are `dart2js` or `dart2wasm` * `--renderer` runs only the test suites that use a particular renderer. Valid - values for this are `html`, `canvakit`, or `skwasm` + values for this are `html`, `canvaskit`, or `skwasm` * `--suite` runs a suite by name. * `--bundle` runs suites that target a particular test bundle. diff --git a/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js b/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js index f7c35aee5294e..9a8176da85341 100644 --- a/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js +++ b/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js @@ -174,7 +174,17 @@ export class FlutterEntrypointLoader { importsPromise = Promise.resolve({}); } const compiledDartApp = await compiledDartAppPromise; - const dartApp = await compiledDartApp.instantiate(await importsPromise); + const dartApp = await compiledDartApp.instantiate(await importsPromise, { + loadDynamicModule: async (wasmUri, mjsUri) => { + const wasmBytes = fetch(resolveUrlWithSegments(entrypointBaseUrl, wasmUri)); + let mjsRuntimeUri = resolveUrlWithSegments(entrypointBaseUrl, mjsUri); + if (this._ttPolicy != null) { + mjsRuntimeUri = this._ttPolicy.createScriptURL(mjsRuntimeUri); + } + const mjsModule = import(mjsRuntimeUri); + return [await wasmBytes, await mjsModule]; + } + }); await dartApp.invokeMain(); } } diff --git a/engine/src/flutter/lib/web_ui/lib/semantics.dart b/engine/src/flutter/lib/web_ui/lib/semantics.dart index 26ca9e708506c..7a8474574592c 100644 --- a/engine/src/flutter/lib/web_ui/lib/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/semantics.dart @@ -683,8 +683,6 @@ class SemanticsUpdateBuilder { required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -742,8 +740,6 @@ class SemanticsUpdateBuilder { tooltip: tooltip, textDirection: textDirection, transform: engine.toMatrix32(transform), - elevation: elevation, - thickness: thickness, childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart index 81f6af4c1cc51..56736933b2573 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart @@ -46,16 +46,17 @@ abstract class HtmlImageElementCodec implements ui.Codec { // Ignoring the returned future on purpose because we're communicating // through the `completer`. - // ignore: unawaited_futures - imgElement! - .decode() - .then((dynamic _) { - chunkCallback?.call(100, 100); - completer.complete(); - }) - .catchError((dynamic e) { - completer.completeError(e.toString()); - }); + unawaited( + imgElement! + .decode() + .then((dynamic _) { + chunkCallback?.call(100, 100); + completer.complete(); + }) + .catchError((dynamic e) { + completer.completeError(e.toString()); + }), + ); return completer.future; } diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart index 825c96f8aa942..c6629275facc4 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -54,6 +54,7 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { static const int _kReduceMotionIndex = 1 << 4; static const int _kHighContrastIndex = 1 << 5; static const int _kOnOffSwitchLabelsIndex = 1 << 6; + static const int _kNoAnnounceIndex = 1 << 7; // A bitfield which represents each enabled feature. final int _index; @@ -72,6 +73,10 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { bool get highContrast => _kHighContrastIndex & _index != 0; @override bool get onOffSwitchLabels => _kOnOffSwitchLabelsIndex & _index != 0; + // This index check is inverted (== 0 vs != 0); far more platforms support + // "announce" than discourage it. + @override + bool get announce => _kNoAnnounceIndex & _index == 0; @override String toString() { @@ -97,6 +102,9 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { if (onOffSwitchLabels) { features.add('onOffSwitchLabels'); } + if (announce) { + features.add('announce'); + } return 'AccessibilityFeatures$features'; } @@ -119,6 +127,7 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { bool? reduceMotion, bool? highContrast, bool? onOffSwitchLabels, + bool? announce, }) { final EngineAccessibilityFeaturesBuilder builder = EngineAccessibilityFeaturesBuilder(0); @@ -129,6 +138,7 @@ class EngineAccessibilityFeatures implements ui.AccessibilityFeatures { builder.reduceMotion = reduceMotion ?? this.reduceMotion; builder.highContrast = highContrast ?? this.highContrast; builder.onOffSwitchLabels = onOffSwitchLabels ?? this.onOffSwitchLabels; + builder.announce = announce ?? this.announce; return builder.build(); } @@ -146,6 +156,9 @@ class EngineAccessibilityFeaturesBuilder { bool get reduceMotion => EngineAccessibilityFeatures._kReduceMotionIndex & _index != 0; bool get highContrast => EngineAccessibilityFeatures._kHighContrastIndex & _index != 0; bool get onOffSwitchLabels => EngineAccessibilityFeatures._kOnOffSwitchLabelsIndex & _index != 0; + // This index check is inverted (== 0 vs != 0); far more platforms support + // "announce" than discourage it. + bool get announce => EngineAccessibilityFeatures._kNoAnnounceIndex & _index == 0; set accessibleNavigation(bool value) { const int accessibleNavigation = EngineAccessibilityFeatures._kAccessibleNavigation; @@ -182,6 +195,12 @@ class EngineAccessibilityFeaturesBuilder { _index = value ? _index | onOffSwitchLabels : _index & ~onOffSwitchLabels; } + set announce(bool value) { + const int noAnnounce = EngineAccessibilityFeatures._kNoAnnounceIndex; + // Since we are using noAnnounce for the embedder, we need to flip the value. + _index = !value ? _index | noAnnounce : _index & ~noAnnounce; + } + /// Creates and returns an instance of EngineAccessibilityFeatures based on the value of _index EngineAccessibilityFeatures build() { return EngineAccessibilityFeatures(_index); @@ -237,8 +256,6 @@ class SemanticsNodeUpdate { this.tooltip, this.textDirection, required this.transform, - required this.elevation, - required this.thickness, required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, @@ -343,12 +360,6 @@ class SemanticsNodeUpdate { /// See [ui.SemanticsUpdateBuilder.updateNode]. final Int32List additionalActions; - /// See [ui.SemanticsUpdateBuilder.updateNode]. - final double elevation; - - /// See [ui.SemanticsUpdateBuilder.updateNode]. - final double thickness; - /// See [ui.SemanticsUpdateBuilder.updateNode]. final int headingLevel; @@ -2485,6 +2496,7 @@ class EngineSemantics { final PlatformConfiguration newConfiguration = EnginePlatformDispatcher.instance.configuration .copyWith(accessibilityFeatures: original.copyWith(accessibleNavigation: value)); EnginePlatformDispatcher.instance.configuration = newConfiguration; + EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged(); _semanticsEnabled = value; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart index 6341eebe77929..12f123a53d19b 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart @@ -47,6 +47,11 @@ mixin CompositionAwareMixin { /// so it is safe to reference it to get the current composingText. String? composingText; + /// The base offset of the composing text in the `InputElement` or `TextAreaElement`. + /// + /// Will be null if composing just started, ended, or no composing is being done. + int? composingBase; + void addCompositionEventHandlers(DomHTMLElement domElement) { domElement.addEventListener(_kCompositionStart, _compositionStartListener); domElement.addEventListener(_kCompositionUpdate, _compositionUpdateListener); @@ -61,6 +66,7 @@ mixin CompositionAwareMixin { void _handleCompositionStart(DomEvent event) { composingText = null; + composingBase = null; } void _handleCompositionUpdate(DomEvent event) { @@ -71,6 +77,7 @@ mixin CompositionAwareMixin { void _handleCompositionEnd(DomEvent event) { composingText = null; + composingBase = null; } EditingState determineCompositionState(EditingState editingState) { @@ -78,15 +85,14 @@ mixin CompositionAwareMixin { return editingState; } - final int composingBase = editingState.extentOffset - composingText!.length; - - if (composingBase < 0) { + composingBase ??= editingState.extentOffset - composingText!.length; + if (composingBase! < 0) { return editingState; } return editingState.copyWith( composingBaseOffset: composingBase, - composingExtentOffset: composingBase + composingText!.length, + composingExtentOffset: composingBase! + composingText!.length, ); } } diff --git a/engine/src/flutter/lib/web_ui/lib/window.dart b/engine/src/flutter/lib/web_ui/lib/window.dart index 6abd944be64ff..251b719678ea6 100644 --- a/engine/src/flutter/lib/web_ui/lib/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/window.dart @@ -115,6 +115,7 @@ abstract class AccessibilityFeatures { bool get reduceMotion; bool get highContrast; bool get onOffSwitchLabels; + bool get announce; } enum Brightness { dark, light } diff --git a/engine/src/flutter/lib/web_ui/test/engine/composition_test.dart b/engine/src/flutter/lib/web_ui/test/engine/composition_test.dart index c75e34d072f97..d5bcebc4b06db 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/composition_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/composition_test.dart @@ -210,6 +210,35 @@ Future testMain() async { ), ); }); + + test('should retain composing base offset if composing text area is changed', () { + const String composingText = '今日は寒い日です'; + + EditingState editingState = EditingState(text: '今日は寒い日です', baseOffset: 0, extentOffset: 8); + + final _MockWithCompositionAwareMixin mockWithCompositionAwareMixin = + _MockWithCompositionAwareMixin(); + mockWithCompositionAwareMixin.composingText = composingText; + + expect( + mockWithCompositionAwareMixin.determineCompositionState(editingState), + editingState.copyWith(composingBaseOffset: 0, composingExtentOffset: 8), + ); + + editingState = editingState.copyWith(baseOffset: 0, extentOffset: 3); + + expect( + mockWithCompositionAwareMixin.determineCompositionState(editingState), + editingState.copyWith(composingBaseOffset: 0, composingExtentOffset: 8), + ); + + editingState = editingState.copyWith(baseOffset: 3, extentOffset: 6); + + expect( + mockWithCompositionAwareMixin.determineCompositionState(editingState), + editingState.copyWith(composingBaseOffset: 0, composingExtentOffset: 8), + ); + }); }); }); diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart index fe7099c0f452f..075e9d16ab644 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -299,6 +299,14 @@ void _testEngineAccessibilityBuilder() { expect(features.onOffSwitchLabels, isTrue); }); + test('announce', () { + // By default this starts off true, see EngineAccessibilityFeatures.announce + expect(features.announce, isTrue); + builder.announce = false; + features = builder.build(); + expect(features.announce, isFalse); + }); + test('reduce motion', () { expect(features.reduceMotion, isFalse); builder.reduceMotion = true; @@ -391,7 +399,10 @@ void _testEngineSemanticsOwner() { }); test('accessibilityFeatures copyWith function works', () { - const EngineAccessibilityFeatures original = EngineAccessibilityFeatures(0); + // Announce is an inverted check, see EngineAccessibilityFeatures.announce. + // Therefore, we need to ensure that the original copy starts with false (1 << 7). + const EngineAccessibilityFeatures original = EngineAccessibilityFeatures(0 | 1 << 7); + EngineAccessibilityFeatures copy = original.copyWith(accessibleNavigation: true); expect(copy.accessibleNavigation, true); expect(copy.boldText, false); @@ -399,6 +410,7 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); + expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(boldText: true); @@ -417,6 +429,7 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); + expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(highContrast: true); @@ -426,6 +439,7 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, true); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); + expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(invertColors: true); @@ -435,6 +449,7 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, true); expect(copy.onOffSwitchLabels, false); + expect(copy.announce, false); expect(copy.reduceMotion, false); copy = original.copyWith(onOffSwitchLabels: true); @@ -446,6 +461,16 @@ void _testEngineSemanticsOwner() { expect(copy.onOffSwitchLabels, true); expect(copy.reduceMotion, false); + copy = original.copyWith(announce: true); + expect(copy.accessibleNavigation, false); + expect(copy.boldText, false); + expect(copy.disableAnimations, false); + expect(copy.highContrast, false); + expect(copy.invertColors, false); + expect(copy.onOffSwitchLabels, false); + expect(copy.announce, true); + expect(copy.reduceMotion, false); + copy = original.copyWith(reduceMotion: true); expect(copy.accessibleNavigation, false); expect(copy.boldText, false); @@ -453,6 +478,7 @@ void _testEngineSemanticsOwner() { expect(copy.highContrast, false); expect(copy.invertColors, false); expect(copy.onOffSwitchLabels, false); + expect(copy.announce, false); expect(copy.reduceMotion, true); }); @@ -4996,8 +5022,6 @@ void updateNode( double scrollPosition = 0.0, double scrollExtentMax = 0.0, double scrollExtentMin = 0.0, - double elevation = 0.0, - double thickness = 0.0, ui.Rect rect = ui.Rect.zero, String identifier = '', String label = '', @@ -5041,8 +5065,6 @@ void updateNode( scrollPosition: scrollPosition, scrollExtentMax: scrollExtentMax, scrollExtentMin: scrollExtentMin, - elevation: elevation, - thickness: thickness, rect: rect, identifier: identifier, label: label, diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart index 24e742249b78d..266dce45845db 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -98,8 +98,6 @@ class SemanticsTester { double? scrollPosition, double? scrollExtentMax, double? scrollExtentMin, - double? elevation, - double? thickness, ui.Rect? rect, String? identifier, String? label, @@ -336,8 +334,6 @@ class SemanticsTester { decreasedValueAttributes: decreasedValueAttributes ?? const [], tooltip: tooltip ?? '', transform: transform != null ? toMatrix32(transform) : Matrix4.identity().storage, - elevation: elevation ?? 0, - thickness: thickness ?? 0, childrenInTraversalOrder: childIds, childrenInHitTestOrder: childIds, additionalActions: additionalActions ?? Int32List(0), diff --git a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart index 73a2bd50a167b..822520cf96845 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart @@ -334,6 +334,19 @@ Future testMain() async { EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged(); }); + test('onAccessibilityFeaturesChanged is called when semantics is enabled', () { + bool a11yChangeInvoked = false; + myWindow.onAccessibilityFeaturesChanged = () { + a11yChangeInvoked = true; + }; + + expect(EngineSemantics.instance.semanticsEnabled, isFalse); + EngineSemantics.instance.semanticsEnabled = true; + + expect(EngineSemantics.instance.semanticsEnabled, isTrue); + expect(a11yChangeInvoked, isTrue); + }); + test('onPlatformMessage preserves the zone', () { final Zone innerZone = Zone.current.fork(); diff --git a/engine/src/flutter/runtime/BUILD.gn b/engine/src/flutter/runtime/BUILD.gn index a0e8610a6e3be..6364215c6bc78 100644 --- a/engine/src/flutter/runtime/BUILD.gn +++ b/engine/src/flutter/runtime/BUILD.gn @@ -118,12 +118,6 @@ source_set("runtime") { "//flutter/third_party/tonic", "//flutter/txt", ] - - if (flutter_runtime_mode != "release" && !is_fuchsia) { - # Only link in Observatory in non-release modes on non-Fuchsia. Fuchsia - # instead puts Observatory into the runner's package. - deps += [ "$dart_src/runtime/observatory:embedded_observatory_archive" ] - } } if (enable_unittests) { diff --git a/engine/src/flutter/runtime/dart_vm.cc b/engine/src/flutter/runtime/dart_vm.cc index 483a27ea2465b..48137ae8ed40c 100644 --- a/engine/src/flutter/runtime/dart_vm.cc +++ b/engine/src/flutter/runtime/dart_vm.cc @@ -28,23 +28,6 @@ #include "third_party/tonic/logging/dart_error.h" #include "third_party/tonic/typed_data/typed_list.h" -namespace dart { -namespace observatory { - -#if !OS_FUCHSIA && !FLUTTER_RELEASE - -// These two symbols are defined in |observatory_archive.cc| which is generated -// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. -// Both of these symbols will be part of the data segment and therefore are read -// only. -extern unsigned int observatory_assets_archive_len; -extern const uint8_t* observatory_assets_archive; - -#endif // !OS_FUCHSIA && !FLUTTER_RELEASE - -} // namespace observatory -} // namespace dart - namespace flutter { // Arguments passed to the Dart VM in all configurations. @@ -158,26 +141,6 @@ bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { void ThreadExitCallback() {} -Dart_Handle GetVMServiceAssetsArchiveCallback() { -#if FLUTTER_RELEASE - return nullptr; -#elif OS_FUCHSIA - fml::UniqueFD fd = fml::OpenFile("pkg/data/observatory.tar", false, - fml::FilePermission::kRead); - fml::FileMapping mapping(fd, {fml::FileMapping::Protection::kRead}); - if (mapping.GetSize() == 0 || mapping.GetMapping() == nullptr) { - FML_LOG(ERROR) << "Fail to load Observatory archive"; - return nullptr; - } - return tonic::DartConverter::ToDart(mapping.GetMapping(), - mapping.GetSize()); -#else - return tonic::DartConverter::ToDart( - ::dart::observatory::observatory_assets_archive, - ::dart::observatory::observatory_assets_archive_len); -#endif -} - static const char kStdoutStreamId[] = "Stdout"; static const char kStderrStreamId[] = "Stderr"; @@ -472,7 +435,6 @@ DartVM::DartVM(const std::shared_ptr& vm_data, params.file_write = dart::bin::WriteFile; params.file_close = dart::bin::CloseFile; params.entropy_source = dart::bin::GetEntropy; - params.get_service_assets = GetVMServiceAssetsArchiveCallback; DartVMInitializer::Initialize(¶ms, settings_.enable_timeline_event_handler, settings_.trace_systrace); diff --git a/engine/src/flutter/shell/platform/BUILD.gn b/engine/src/flutter/shell/platform/BUILD.gn index 63e9901643614..b5196cb90a3ec 100644 --- a/engine/src/flutter/shell/platform/BUILD.gn +++ b/engine/src/flutter/shell/platform/BUILD.gn @@ -22,6 +22,8 @@ group("platform") { } else if (is_fuchsia) { import("//flutter/tools/fuchsia/gn-sdk/src/gn_configs.gni") deps = [ "fuchsia" ] + } else if (is_qnx) { + deps = [] } else { assert(false, "Unknown/Unsupported platform.") } diff --git a/engine/src/flutter/shell/platform/android/flutter_main.cc b/engine/src/flutter/shell/platform/android/flutter_main.cc index 4e56c418372a4..96e9d78cc973a 100644 --- a/engine/src/flutter/shell/platform/android/flutter_main.cc +++ b/engine/src/flutter/shell/platform/android/flutter_main.cc @@ -45,6 +45,23 @@ namespace { fml::jni::ScopedJavaGlobalRef* g_flutter_jni_class = nullptr; +// Workaround for crashes in Vivante GL driver on Android. +// +// See: +// * https://github.com/flutter/flutter/issues/167850 +// * http://crbug.com/141785 +#ifdef FML_OS_ANDROID +bool IsVivante() { + char product_model[PROP_VALUE_MAX]; + __system_property_get("ro.hardware.egl", product_model); + return strcmp(product_model, "VIVANTE") == 0; +} +#else +bool IsVivante() { + return false; +} +#endif // FML_OS_ANDROID + } // anonymous namespace FlutterMain::FlutterMain(const flutter::Settings& settings, @@ -274,7 +291,7 @@ AndroidRenderingAPI FlutterMain::SelectedRenderingAPI( #endif if (settings.enable_impeller && - api_level >= kMinimumAndroidApiLevelForImpeller) { + api_level >= kMinimumAndroidApiLevelForImpeller && !IsVivante()) { return AndroidRenderingAPI::kImpellerAutoselect; } diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 99dc1cdaa8b97..71a0fddd7c174 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -490,6 +490,7 @@ public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) { this.accessibilityManager.addTouchExplorationStateChangeListener( touchExplorationStateChangeListener); + accessibilityFeatureFlags |= AccessibilityFeature.NO_ANNOUNCE.value; // Tell Flutter whether animations should initially be enabled or disabled. Then register a // listener to be notified of changes in the future. animationScaleObserver.onChange(false); @@ -2174,7 +2175,8 @@ private enum AccessibilityFeature { BOLD_TEXT(1 << 3), // NOT SUPPORTED REDUCE_MOTION(1 << 4), // NOT SUPPORTED HIGH_CONTRAST(1 << 5), // NOT SUPPORTED - ON_OFF_SWITCH_LABELS(1 << 6); // NOT SUPPORTED + ON_OFF_SWITCH_LABELS(1 << 6), // NOT SUPPORTED + NO_ANNOUNCE(1 << 7); final int value; diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index b2ed50a3b4d19..552f217fffeda 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -66,6 +66,11 @@ @RunWith(AndroidJUnit4.class) public class AccessibilityBridgeTest { + private static final int ACCESSIBILITY_FEATURE_NAVIGATION = 1 << 0; + private static final int ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS = 1 << 2; + private static final int ACCESSIBILITY_FEATURE_BOLD_TEXT = 1 << 3; + private static final int ACCESSIBILITY_FEATURE_NO_ANNOUNCE = 1 << 7; + @Test public void itDescribesNonTextFieldsWithAContentDescription() { AccessibilityBridge accessibilityBridge = setUpBridge(); @@ -135,6 +140,26 @@ public void itTakesGlobalCoordinatesOfFlutterViewIntoAccount() { assertEquals(position, outBoundsInScreen.top); } + @Test + public void itSetsNoAnnounceAccessibleFlagByDefault() { + AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); + AccessibilityManager mockManager = mock(AccessibilityManager.class); + View mockRootView = mock(View.class); + Context context = mock(Context.class); + when(mockRootView.getContext()).thenReturn(context); + when(context.getPackageName()).thenReturn("test"); + when(mockManager.isTouchExplorationEnabled()).thenReturn(false); + setUpBridge( + /*rootAccessibilityView=*/ mockRootView, + /*accessibilityChannel=*/ mockChannel, + /*accessibilityManager=*/ mockManager, + /*contentResolver=*/ null, + /*accessibilityViewEmbedder=*/ mockViewEmbedder, + /*platformViewsAccessibilityDelegate=*/ null); + verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); + } + @Test public void itSetsAccessibleNavigation() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); @@ -158,18 +183,20 @@ public void itSetsAccessibleNavigation() { verify(mockManager).addTouchExplorationStateChangeListener(listenerCaptor.capture()); assertEquals(accessibilityBridge.getAccessibleNavigation(), false); - verify(mockChannel).setAccessibilityFeatures(0); + verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); reset(mockChannel); // Simulate assistive technology accessing accessibility tree. accessibilityBridge.createAccessibilityNodeInfo(0); - verify(mockChannel).setAccessibilityFeatures(1); + verify(mockChannel) + .setAccessibilityFeatures( + ACCESSIBILITY_FEATURE_NAVIGATION | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); assertEquals(accessibilityBridge.getAccessibleNavigation(), true); // Simulate turning off TalkBack. reset(mockChannel); listenerCaptor.getValue().onTouchExplorationStateChanged(false); - verify(mockChannel).setAccessibilityFeatures(0); + verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); assertEquals(accessibilityBridge.getAccessibleNavigation(), false); } @@ -1157,7 +1184,9 @@ public void itSetsBoldTextFlagCorrectly() { /*accessibilityViewEmbedder=*/ mockViewEmbedder, /*platformViewsAccessibilityDelegate=*/ null); - verify(mockChannel).setAccessibilityFeatures(1 << 3); + verify(mockChannel) + .setAccessibilityFeatures( + ACCESSIBILITY_FEATURE_BOLD_TEXT | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); reset(mockChannel); // Now verify that clearing the BOLD_TEXT flag doesn't touch any of the other flags. @@ -1179,7 +1208,9 @@ public void itSetsBoldTextFlagCorrectly() { // constructor, verify that the latest argument is correct ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class); verify(mockChannel, atLeastOnce()).setAccessibilityFeatures(captor.capture()); - assertEquals(1 << 2 /* DISABLE_ANIMATION */, captor.getValue().intValue()); + assertEquals( + ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS | ACCESSIBILITY_FEATURE_NO_ANNOUNCE, + captor.getValue().intValue()); // Set back to default Settings.Global.putFloat(null, "transition_animation_scale", 1.0f); @@ -1874,19 +1905,21 @@ public void testItSetsDisableAnimationsFlagBasedOnTransitionAnimationScale() { ContentObserver observer = observerCaptor.getValue(); // Initial state - verify(mockChannel).setAccessibilityFeatures(0); + verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); reset(mockChannel); // Animations are disabled Settings.Global.putFloat(mockContentResolver, "transition_animation_scale", 0.0f); observer.onChange(false); - verify(mockChannel).setAccessibilityFeatures(1 << 2); + verify(mockChannel) + .setAccessibilityFeatures( + ACCESSIBILITY_FEATURE_DISABLE_ANIMATIONS | ACCESSIBILITY_FEATURE_NO_ANNOUNCE); reset(mockChannel); // Animations are enabled Settings.Global.putFloat(mockContentResolver, "transition_animation_scale", 1.0f); observer.onChange(false); - verify(mockChannel).setAccessibilityFeatures(0); + verify(mockChannel).setAccessibilityFeatures(ACCESSIBILITY_FEATURE_NO_ANNOUNCE); } @Test diff --git a/engine/src/flutter/shell/platform/common/accessibility_bridge.cc b/engine/src/flutter/shell/platform/common/accessibility_bridge.cc index 1913a580c509e..b471da88178e0 100644 --- a/engine/src/flutter/shell/platform/common/accessibility_bridge.cc +++ b/engine/src/flutter/shell/platform/common/accessibility_bridge.cc @@ -596,8 +596,6 @@ AccessibilityBridge::FromFlutterSemanticsNode( result.scroll_position = flutter_node.scroll_position; result.scroll_extent_max = flutter_node.scroll_extent_max; result.scroll_extent_min = flutter_node.scroll_extent_min; - result.elevation = flutter_node.elevation; - result.thickness = flutter_node.thickness; if (flutter_node.label) { result.label = std::string(flutter_node.label); } diff --git a/engine/src/flutter/shell/platform/common/accessibility_bridge.h b/engine/src/flutter/shell/platform/common/accessibility_bridge.h index 8126c1ce7b65a..6b6f575837927 100644 --- a/engine/src/flutter/shell/platform/common/accessibility_bridge.h +++ b/engine/src/flutter/shell/platform/common/accessibility_bridge.h @@ -170,8 +170,6 @@ class AccessibilityBridge double scroll_position; double scroll_extent_max; double scroll_extent_min; - double elevation; - double thickness; std::string label; std::string hint; std::string value; diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index d2297ee1ee1fe..32f7ec124a135 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -34,6 +34,7 @@ _flutter_framework_headers = [ "framework/Headers/FlutterPlatformViews.h", "framework/Headers/FlutterPlugin.h", "framework/Headers/FlutterPluginAppLifeCycleDelegate.h", + "framework/Headers/FlutterSceneDelegate.h", "framework/Headers/FlutterViewController.h", ] @@ -75,6 +76,7 @@ source_set("flutter_framework_source") { sources = [ "framework/Source/FlutterAppDelegate.mm", + "framework/Source/FlutterAppDelegate_Internal.h", "framework/Source/FlutterCallbackCache.mm", "framework/Source/FlutterCallbackCache_Internal.h", "framework/Source/FlutterChannelKeyResponder.h", @@ -93,6 +95,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterKeySecondaryResponder.h", "framework/Source/FlutterKeyboardManager.h", "framework/Source/FlutterKeyboardManager.mm", + "framework/Source/FlutterLaunchEngine.h", + "framework/Source/FlutterLaunchEngine.m", "framework/Source/FlutterMetalLayer.h", "framework/Source/FlutterMetalLayer.mm", "framework/Source/FlutterOverlayView.h", @@ -106,6 +110,7 @@ source_set("flutter_framework_source") { "framework/Source/FlutterPluginAppLifeCycleDelegate.mm", "framework/Source/FlutterRestorationPlugin.h", "framework/Source/FlutterRestorationPlugin.mm", + "framework/Source/FlutterSceneDelegate.m", "framework/Source/FlutterSemanticsScrollView.h", "framework/Source/FlutterSemanticsScrollView.mm", "framework/Source/FlutterSharedApplication.h", @@ -250,6 +255,7 @@ if (enable_ios_unittests) { "framework/Source/FlutterFakeKeyEvents.h", "framework/Source/FlutterFakeKeyEvents.mm", "framework/Source/FlutterKeyboardManagerTest.mm", + "framework/Source/FlutterLaunchEngineTest.mm", "framework/Source/FlutterMetalLayerTest.mm", "framework/Source/FlutterPlatformPluginTest.mm", "framework/Source/FlutterPlatformViewsTest.mm", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h index 705dfcb028d2a..624cf09bc99ba 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h @@ -18,6 +18,7 @@ #import "FlutterPlatformViews.h" #import "FlutterPlugin.h" #import "FlutterPluginAppLifeCycleDelegate.h" +#import "FlutterSceneDelegate.h" #import "FlutterTexture.h" #import "FlutterViewController.h" diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h index 126fb00bc6a9a..fce4fd33a4a83 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h @@ -38,7 +38,8 @@ FLUTTER_DARWIN_EXPORT * * This was introduced to help users migrate code from the FlutterAppDelegate * when UISceneDelegate was adopted. Using - * FlutterViewController.pluginRegistrant should be preferred. + * FlutterViewController.pluginRegistrant should be preferred since it doesn't + * rely on the FlutterAppDelegate. */ @property(nonatomic, strong, nullable) NSObject* pluginRegistrant; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h new file mode 100644 index 0000000000000..27f768355ecd7 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The UISceneDelegate used by Flutter by default. + * + * This class is typically specified as the UISceneDelegate in the Info.plist. + */ +@interface FlutterSceneDelegate : NSObject +@property(nonatomic, strong, nullable) UIWindow* window; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm index e15a0a059fc0f..f1845fbca63ba 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm @@ -9,6 +9,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" @@ -26,6 +27,7 @@ @interface FlutterAppDelegate () { } @property(nonatomic, copy) FlutterViewController* (^rootFlutterViewControllerGetter)(void); @property(nonatomic, strong) FlutterPluginAppLifeCycleDelegate* lifeCycleDelegate; +@property(nonatomic, strong) FlutterLaunchEngine* launchEngine; @end @implementation FlutterAppDelegate @@ -33,10 +35,15 @@ @implementation FlutterAppDelegate - (instancetype)init { if (self = [super init]) { _lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; + _launchEngine = [[FlutterLaunchEngine alloc] init]; } return self; } +- (nullable FlutterEngine*)takeLaunchEngine { + return [self.launchEngine takeEngine]; +} + - (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions { return [self.lifeCycleDelegate application:application @@ -256,7 +263,7 @@ - (void)setPluginRegistrant:(NSObject*)pluginRegistrant if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey]; } - return nil; + return [self.launchEngine.engine registrarForPlugin:pluginKey]; } - (BOOL)hasPlugin:(NSString*)pluginKey { @@ -264,7 +271,7 @@ - (BOOL)hasPlugin:(NSString*)pluginKey { if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] hasPlugin:pluginKey]; } - return false; + return [self.launchEngine.engine hasPlugin:pluginKey]; } - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { @@ -272,7 +279,7 @@ - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] valuePublishedByPlugin:pluginKey]; } - return nil; + return [self.launchEngine.engine valuePublishedByPlugin:pluginKey]; } #pragma mark - Selectors handling diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm index 184c1c6010df6..7088b18f35bd4 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm @@ -8,6 +8,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h" @@ -154,6 +155,20 @@ - (void)testReleasesWindowOnDealloc { XCTAssertNil(weakWindow); } +- (void)testGrabLaunchEngine { + // Clear out the mocking of the root view controller. + [self.mockMainBundle stopMocking]; + self.appDelegate.rootFlutterViewControllerGetter = nil; + // Working with plugins forces the creation of an engine. + XCTAssertFalse([self.appDelegate hasPlugin:@"hello"]); + XCTAssertNotNil([self.appDelegate takeLaunchEngine]); + XCTAssertNil([self.appDelegate takeLaunchEngine]); +} + +- (void)testGrabLaunchEngineWithoutPlugins { + XCTAssertNil([self.appDelegate takeLaunchEngine]); +} + #pragma mark - Deep linking - (void)testUniversalLinkPushRouteInformation { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h new file mode 100644 index 0000000000000..b90796d7514aa --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h" + +@interface FlutterAppDelegate () + +- (nullable FlutterEngine*)takeLaunchEngine; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h new file mode 100644 index 0000000000000..5a054f4719422 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" + +/** + * A lazy container for an engine that will only dispense one engine. + * + * This is used to hold an engine for plugin registration when the + * GeneratedPluginRegistrant is called on a FlutterAppDelegate before the first + * FlutterViewController is set up. This is the typical flow after the + * UISceneDelegate migration. + * + * The launch engine is intended to work only with first FlutterViewController + * instantiated with a NIB since that is the only FlutterEngine that registers + * plugins through the FlutterAppDelegate. + */ +@interface FlutterLaunchEngine : NSObject + +/** + * Accessor for the launch engine. + * + * Getting this may allocate an engine. + */ +@property(nonatomic, strong, nullable, readonly) FlutterEngine* engine; + +/** + * Take ownership of the launch engine. + * + * After this is called `self.engine` and `takeEngine` will always return nil. + */ +- (nullable FlutterEngine*)takeEngine; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m new file mode 100644 index 0000000000000..6dbb6a0b93311 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m @@ -0,0 +1,52 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" + +@interface FlutterLaunchEngine () { + BOOL _didTakeEngine; + FlutterEngine* _engine; +} +@end + +@implementation FlutterLaunchEngine + +- (instancetype)init { + self = [super init]; + if (self) { + self->_didTakeEngine = NO; + } + return self; +} + +- (FlutterEngine*)engine { + if (!_didTakeEngine && !_engine) { + // `allowHeadlessExecution` is set to `YES` since that has always been the + // default behavior. Technically, someone could have set it to `NO` in their + // nib and it would be ignored here. There is no documented usage of this + // though. + // `restorationEnabled` is set to `YES` since a FlutterViewController + // without restoration will have a nil restorationIdentifier leading no + // restoration data being saved. So, it is safe to turn this on in the event + // that someone does not want it. + _engine = [[FlutterEngine alloc] initWithName:@"io.flutter" + project:[[FlutterDartProject alloc] init] + allowHeadlessExecution:YES + restorationEnabled:YES]; + // Run engine with default values like initialRoute. Specifying these in + // the FlutterViewController was not supported so it's safe to use the + // defaults. + [_engine run]; + } + return _engine; +} + +- (nullable FlutterEngine*)takeEngine { + FlutterEngine* result = _engine; + _engine = nil; + _didTakeEngine = YES; + return result; +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm new file mode 100644 index 0000000000000..e3a28edac0daa --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import +#import +#import +#import + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" + +FLUTTER_ASSERT_ARC; + +@interface FlutterLaunchEngineTest : XCTestCase +@end + +@implementation FlutterLaunchEngineTest + +- (void)testSimple { + FlutterLaunchEngine* launchEngine = [[FlutterLaunchEngine alloc] init]; + XCTAssertTrue(launchEngine.engine); + XCTAssertTrue([launchEngine takeEngine]); + XCTAssertFalse(launchEngine.engine); +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m new file mode 100644 index 0000000000000..64a1774ef46dc --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h" + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" + +FLUTTER_ASSERT_ARC + +@implementation FlutterSceneDelegate + +- (void)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(UISceneConnectionOptions*)connectionOptions { + NSObject* appDelegate = FlutterSharedApplication.application.delegate; + if (appDelegate.window.rootViewController) { + NSLog(@"WARNING - The UIApplicationDelegate is setting up the UIWindow and " + @"UIWindow.rootViewController at launch. This was deprecated after the " + @"UISceneDelegate adoption. Setup logic should be moved to a UISceneDelegate."); + // If this is not nil we are running into a case where someone is manually + // performing root view controller setup in the UIApplicationDelegate. + UIWindowScene* windowScene = (UIWindowScene*)scene; + self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; + self.window.rootViewController = appDelegate.window.rootViewController; + appDelegate.window = self.window; + [self.window makeKeyAndVisible]; + } +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 71aca23a4074e..d0b377d6419c0 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -17,11 +17,13 @@ #include "flutter/shell/common/thread_host.h" #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h" #import "flutter/shell/platform/darwin/common/framework/Source/FlutterBinaryMessengerRelay.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterChannelKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEmbedderKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyPrimaryResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" @@ -258,15 +260,33 @@ - (instancetype)init { - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project initialRoute:(nullable NSString*)initialRoute { - // Need the project to get settings for the view. Initializing it here means - // the Engine class won't initialize it later. - if (!project) { - project = [[FlutterDartProject alloc] init]; - } - FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"io.flutter" - project:project - allowHeadlessExecution:self.engineAllowHeadlessExecution - restorationEnabled:self.restorationIdentifier != nil]; + id appDelegate = FlutterSharedApplication.application.delegate; + FlutterEngine* engine; + if ([appDelegate respondsToSelector:@selector(takeLaunchEngine)]) { + if (self.nibName) { + // Only grab the launch engine if it was created with a nib. + // FlutterViewControllers created from nibs can't specify their initial + // routes so it's safe to take it. + engine = [appDelegate takeLaunchEngine]; + } else { + // If we registered plugins with a FlutterAppDelegate without a xib, throw + // away the engine that was registered through the FlutterAppDelegate. + // That's not a valid usage of the API. + [appDelegate takeLaunchEngine]; + } + } + if (!engine) { + // Need the project to get settings for the view. Initializing it here means + // the Engine class won't initialize it later. + if (!project) { + project = [[FlutterDartProject alloc] init]; + } + + engine = [[FlutterEngine alloc] initWithName:@"io.flutter" + project:project + allowHeadlessExecution:self.engineAllowHeadlessExecution + restorationEnabled:self.restorationIdentifier != nil]; + } if (!engine) { return; } @@ -275,7 +295,7 @@ - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project _engine = engine; _flutterView = [[FlutterView alloc] initWithDelegate:_engine opaque:_viewOpaque - enableWideGamut:project.isWideGamutEnabled]; + enableWideGamut:engine.project.isWideGamutEnabled]; [_engine createShell:nil libraryURI:nil initialRoute:initialRoute]; _engineNeedsLaunch = YES; _ongoingTouches = [[NSMutableSet alloc] init]; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index ac92f4bddef0c..9fa890faf2084 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -13,6 +13,7 @@ #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterHourFormat.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEmbedderKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFakeKeyEvents.h" @@ -119,6 +120,10 @@ @interface FlutterEmbedderKeyResponder (Tests) @property(nonatomic, copy, readonly) FlutterSendKeyEvent sendEvent; @end +@interface NSObject (Tests) +@property(nonatomic, strong) FlutterEngine* mockLaunchEngine; +@end + @interface FlutterViewController (Tests) @property(nonatomic, assign) double targetViewInsetBottom; @@ -2490,4 +2495,28 @@ - (void)testAppDelegatePluginRegistrant { OCMVerify([mockRegistrant registerWithRegistry:viewController]); } +- (void)testGrabLaunchEngine { + id appDelegate = [[UIApplication sharedApplication] delegate]; + XCTAssertTrue([appDelegate respondsToSelector:@selector(setMockLaunchEngine:)]); + [appDelegate setMockLaunchEngine:self.mockEngine]; + UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Flutter" bundle:nil]; + XCTAssertTrue(storyboard); + FlutterViewController* viewController = + (FlutterViewController*)[storyboard instantiateInitialViewController]; + XCTAssertTrue(viewController); + XCTAssertTrue([viewController isKindOfClass:[FlutterViewController class]]); + XCTAssertEqual(viewController.engine, self.mockEngine); + [appDelegate setMockLaunchEngine:nil]; +} + +- (void)testDoesntGrabLaunchEngine { + id appDelegate = [[UIApplication sharedApplication] delegate]; + XCTAssertTrue([appDelegate respondsToSelector:@selector(setMockLaunchEngine:)]); + [appDelegate setMockLaunchEngine:self.mockEngine]; + FlutterViewController* flutterViewController = [[FlutterViewController alloc] init]; + XCTAssertNotNil(flutterViewController.engine); + XCTAssertNotEqual(flutterViewController.engine, self.mockEngine); + [appDelegate setMockLaunchEngine:nil]; +} + @end diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm index 22ade65600750..5cd463e8f83af 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm @@ -10,6 +10,7 @@ #include #include +#include "flutter/common/constants.h" #include "flutter/fml/platform/darwin/string_range_sanitization.h" #include "flutter/shell/platform/common/text_editing_delta.h" #include "flutter/shell/platform/common/text_input_model.h" @@ -425,8 +426,12 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { } _activeModel = std::make_unique(); - NSNumber* viewId = config[kViewId]; - _currentViewController = [_delegate viewControllerForIdentifier:viewId.longLongValue]; + FlutterViewIdentifier viewId = flutter::kFlutterImplicitViewId; + NSObject* requestViewId = config[kViewId]; + if ([requestViewId isKindOfClass:[NSNumber class]]) { + viewId = [(NSNumber*)requestViewId longLongValue]; + } + _currentViewController = [_delegate viewControllerForIdentifier:viewId]; FML_DCHECK(_currentViewController != nil); } } else if ([method isEqualToString:kShowMethod]) { diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm index d88f0535464e7..0377f5204698e 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm @@ -60,6 +60,7 @@ - (bool)testClearClientDuringComposing; @interface FlutterTextInputPluginTestDelegate : NSObject { id _binaryMessenger; FlutterViewController* _viewController; + FlutterViewController* _implicitViewController; } @end @@ -80,10 +81,22 @@ - (instancetype)initWithBinaryMessenger:(id)messenger return self; } +- (instancetype)initWithBinaryMessenger:(id)messenger + implicitViewController:(FlutterViewController*)viewController { + self = [super init]; + if (self) { + _binaryMessenger = messenger; + _implicitViewController = viewController; + } + return self; +} + - (nullable FlutterViewController*)viewControllerForIdentifier: (FlutterViewIdentifier)viewIdentifier { if (viewIdentifier == kViewId) { return _viewController; + } else if (viewIdentifier == flutter::kFlutterImplicitViewId) { + return _implicitViewController; } else { return nil; } @@ -2394,4 +2407,32 @@ - (bool)testSelectorsNotForwardedToFrameworkIfNoClient { ASSERT_TRUE(plugin.clipsToBounds); } +TEST(FlutterTextInputPluginTest, WorksWithoutViewId) { + id engineMock = flutter::testing::CreateMockFlutterEngine(@""); + id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + OCMStub( // NOLINT(google-objc-avoid-throwing-exception) + [engineMock binaryMessenger]) + .andReturn(binaryMessengerMock); + + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock + nibName:@"" + bundle:nil]; + + FlutterTextInputPluginTestDelegate* delegate = + [[FlutterTextInputPluginTestDelegate alloc] initWithBinaryMessenger:binaryMessengerMock + implicitViewController:viewController]; + + FlutterTextInputPlugin* plugin = [[FlutterTextInputPlugin alloc] initWithDelegate:delegate]; + + NSDictionary* setClientConfig = @{ + // omit viewId + }; + [plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient" + arguments:@[ @(1), setClientConfig ]] + result:^(id){ + }]; + + ASSERT_TRUE(plugin.currentViewController == viewController); +} + } // namespace flutter::testing diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index aebf1fedb99e8..d849e7dca12de 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -16,6 +16,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/native_library.h" +#include "flutter/fml/status_or.h" #include "flutter/fml/thread.h" #include "third_party/dart/runtime/bin/elf_loader.h" #include "third_party/dart/runtime/include/dart_native_api.h" @@ -1529,12 +1530,14 @@ CreateEmbedderRenderTarget( return render_target; } -static std::pair, - bool /* halt engine launch if true */> +/// Creates an EmbedderExternalViewEmbedder. +/// +/// When a non-OK status is returned, engine startup should be halted. +static fml::StatusOr> InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor, bool enable_impeller) { if (compositor == nullptr) { - return {nullptr, false}; + return std::unique_ptr{nullptr}; } auto c_create_callback = @@ -1550,15 +1553,15 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor, // Make sure the required callbacks are present if (!c_create_callback || !c_collect_callback) { - FML_LOG(ERROR) << "Required compositor callbacks absent."; - return {nullptr, true}; + return fml::Status(fml::StatusCode::kInvalidArgument, + "Required compositor callbacks absent."); } // Either the present view or the present layers callback must be provided. if ((!c_present_view_callback && !c_present_callback) || (c_present_view_callback && c_present_callback)) { - FML_LOG(ERROR) << "Either present_layers_callback or present_view_callback " - "must be provided but not both."; - return {nullptr, true}; + return fml::Status(fml::StatusCode::kInvalidArgument, + "Either present_layers_callback or " + "present_view_callback must be provided but not both."); } FlutterCompositor captured_compositor = *compositor; @@ -1601,10 +1604,9 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor, }; } - return {std::make_unique( - avoid_backing_store_cache, create_render_target_callback, - present_callback), - false}; + return std::make_unique( + avoid_backing_store_cache, create_render_target_callback, + present_callback); } // Translates embedder metrics to engine metrics, or returns a string on error. @@ -2258,7 +2260,8 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, auto external_view_embedder_result = InferExternalViewEmbedderFromArgs( SAFE_ACCESS(args, compositor, nullptr), settings.enable_impeller); - if (external_view_embedder_result.second) { + if (!external_view_embedder_result.ok()) { + FML_LOG(ERROR) << external_view_embedder_result.status().message(); return LOG_EMBEDDER_ERROR(kInvalidArguments, "Compositor arguments were invalid."); } @@ -2276,7 +2279,8 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, auto on_create_platform_view = InferPlatformViewCreationCallback( config, user_data, platform_dispatch_table, - std::move(external_view_embedder_result.first), settings.enable_impeller); + std::move(external_view_embedder_result.value()), + settings.enable_impeller); if (!on_create_platform_view) { return LOG_EMBEDDER_ERROR( diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index 07f48914d223e..a097891756133 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -105,6 +105,8 @@ typedef enum { kFlutterAccessibilityFeatureHighContrast = 1 << 5, /// Request to show on/off labels inside switches. kFlutterAccessibilityFeatureOnOffSwitchLabels = 1 << 6, + /// Indicate the platform does not support announcements. + kFlutterAccessibilityFeatureNoAnnounce = 1 << 7, } FlutterAccessibilityFeature; /// The set of possible actions that can be conveyed to a semantics node. diff --git a/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc b/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc index 76f4d32680eaa..6376d49eedb62 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc @@ -150,8 +150,8 @@ void EmbedderSemanticsUpdate::AddNode(const SemanticsNode& node) { node.scrollPosition, node.scrollExtentMax, node.scrollExtentMin, - node.elevation, - node.thickness, + 0.0, + 0.0, node.label.c_str(), node.hint.c_str(), node.value.c_str(), @@ -251,8 +251,8 @@ void EmbedderSemanticsUpdate2::AddNode(const SemanticsNode& node) { node.scrollPosition, node.scrollExtentMax, node.scrollExtentMin, - node.elevation, - node.thickness, + 0.0, + 0.0, node.label.c_str(), node.hint.c_str(), node.value.c_str(), diff --git a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart index c83292dc23d60..027923df8e599 100644 --- a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart @@ -185,8 +185,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -220,8 +218,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -259,8 +255,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -295,8 +289,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -368,8 +360,6 @@ Future a11y_string_attributes() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: "It's a number", hintAttributes: [ LocaleStringAttribute( @@ -1683,8 +1673,6 @@ Future a11y_main_multi_view() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', diff --git a/engine/src/flutter/shell/platform/fuchsia/dart_runner/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/dart_runner/BUILD.gn index c42682d0f541f..ad59180b71f24 100644 --- a/engine/src/flutter/shell/platform/fuchsia/dart_runner/BUILD.gn +++ b/engine/src/flutter/shell/platform/fuchsia/dart_runner/BUILD.gn @@ -169,10 +169,6 @@ template("aot_runner_package") { deps += [ "vmservice:vmservice_snapshot", "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:dart_aot_runner", - - # TODO(kaushikiska): Figure out how to get the profiler symbols for `libdart_aotruntime` - # "$dart_src/runtime:libdart_aotruntime", - observatory_target, ] } @@ -195,10 +191,6 @@ template("aot_runner_package") { path = vmservice_snapshot dest = "vmservice_snapshot.so" }, - { - path = rebase_path(observatory_archive_file) - dest = "observatory.tar" - }, { path = dart_profiler_symbols dest = "dart_aot_runner.dartprofilersymbols" @@ -222,10 +214,7 @@ template("jit_runner_package") { ] if (!invoker.product) { - deps += [ - "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:dart_jit_runner", - observatory_target, - ] + deps += [ "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:dart_jit_runner" ] } binary = "dart_jit${product_suffix}_runner" @@ -247,10 +236,6 @@ template("jit_runner_package") { if (!invoker.product) { resources += [ - { - path = rebase_path(observatory_archive_file) - dest = "observatory.tar" - }, { path = rebase_path( get_label_info( diff --git a/engine/src/flutter/shell/platform/fuchsia/dart_runner/dart_runner.cc b/engine/src/flutter/shell/platform/fuchsia/dart_runner/dart_runner.cc index 1d140723eb6e6..767488d121d9a 100644 --- a/engine/src/flutter/shell/platform/fuchsia/dart_runner/dart_runner.cc +++ b/engine/src/flutter/shell/platform/fuchsia/dart_runner/dart_runner.cc @@ -228,9 +228,6 @@ DartRunner::DartRunner(sys::ComponentContext* context) : context_(context) { params.shutdown_isolate = IsolateShutdownCallback; params.cleanup_group = IsolateGroupCleanupCallback; params.entropy_source = EntropySource; -#if !defined(DART_PRODUCT) - params.get_service_assets = GetVMServiceAssetsArchiveCallback; -#endif error = Dart_Initialize(¶ms); if (error) FML_LOG(FATAL) << "Dart_Initialize failed: " << error; diff --git a/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.cc b/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.cc index 59d9cb8fbf999..4d6a8748f3953 100644 --- a/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.cc +++ b/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.cc @@ -197,18 +197,4 @@ Dart_Isolate CreateServiceIsolate( return isolate; } // namespace dart_runner -Dart_Handle GetVMServiceAssetsArchiveCallback() { - dart_utils::MappedResource vm_service_tar; - if (!dart_utils::MappedResource::LoadFromNamespace( - nullptr, "/pkg/data/observatory.tar", vm_service_tar)) { - FML_LOG(ERROR) << "Failed to load Observatory assets"; - return nullptr; - } - // TODO(rmacnak): Should we avoid copying the tar? Or does the service - // library not hold onto it anyway? - return tonic::DartConverter::ToDart( - reinterpret_cast(vm_service_tar.address()), - vm_service_tar.size()); -} - } // namespace dart_runner diff --git a/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.h b/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.h index 4e87f63876911..5b5663c8672a8 100644 --- a/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.h +++ b/engine/src/flutter/shell/platform/fuchsia/dart_runner/service_isolate.h @@ -13,8 +13,6 @@ Dart_Isolate CreateServiceIsolate(const char* uri, Dart_IsolateFlags* flags, char** error); -Dart_Handle GetVMServiceAssetsArchiveCallback(); - } // namespace dart_runner #endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_RUNNER_SERVICE_ISOLATE_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn index a7408d7ee5f0d..99c037953d4f6 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn @@ -312,10 +312,7 @@ template("jit_runner") { ] if (!product) { - deps += [ - "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_jit_runner", - observatory_target, - ] + deps += [ "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_jit_runner" ] } binary = "flutter_jit${product_suffix}_runner" @@ -329,10 +326,6 @@ template("jit_runner") { if (!product) { resources += [ - { - path = rebase_path(observatory_archive_file) - dest = "observatory.tar" - }, { path = rebase_path( get_label_info( @@ -381,10 +374,7 @@ template("aot_runner") { deps = [ ":aot${product_suffix}" ] if (!product) { - deps += [ - "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_aot_runner", - observatory_target, - ] + deps += [ "//flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_aot_runner" ] } binary = "flutter_aot${product_suffix}_runner" @@ -398,10 +388,6 @@ template("aot_runner") { if (!product) { resources += [ - { - path = rebase_path(observatory_archive_file) - dest = "observatory.tar" - }, { path = rebase_path( get_label_info( diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc index e7c9ecf825a06..e67ce3264e211 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc @@ -279,10 +279,8 @@ fuchsia::ui::gfx::BoundingBox AccessibilityBridge::GetNodeLocation( fuchsia::ui::gfx::BoundingBox box; box.min.x = node.rect.fLeft; box.min.y = node.rect.fTop; - box.min.z = static_cast(node.elevation); box.max.x = node.rect.fRight; box.max.y = node.rect.fBottom; - box.max.z = static_cast(node.thickness); return box; } diff --git a/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.cc b/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.cc index 41445c980f52c..aa9bbf085f39e 100644 --- a/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.cc +++ b/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.cc @@ -134,27 +134,47 @@ bool ElfSnapshot::Load(fdio_ns_t* namespc, const std::string& path) { } bool ElfSnapshot::Load(int dirfd, const std::string& path) { - const int fd = OpenFdExec(path, dirfd); - if (fd < 0) { + fml::UniqueFD fd(OpenFdExec(path, dirfd)); + if (!fd.is_valid()) { FML_LOG(ERROR) << "Failed to open VMO for " << path << " from dir."; return false; } return Load(fd); } -bool ElfSnapshot::Load(int fd) { - const char* error; - handle_ = Dart_LoadELF_Fd(fd, 0, &error, &vm_data_, &vm_instrs_, - &isolate_data_, &isolate_instrs_); +bool ElfSnapshot::Load(const fml::UniqueFD& fd) { + zx_handle_t vmo = ZX_HANDLE_INVALID; + zx_status_t status = fdio_get_vmo_exec(fd.get(), &vmo); + if (status != ZX_OK) { + FML_LOG(ERROR) << "Failed load ELF: " << zx_status_get_string(status); + return false; + } + handle_ = dlopen_vmo(vmo, RTLD_LAZY); if (handle_ == nullptr) { + const char* error = dlerror(); FML_LOG(ERROR) << "Failed load ELF: " << error; return false; } + + vm_data_ = + reinterpret_cast(dlsym(handle_, kVmSnapshotDataCSymbol)); + vm_instrs_ = reinterpret_cast( + dlsym(handle_, kVmSnapshotInstructionsCSymbol)); + isolate_data_ = reinterpret_cast( + dlsym(handle_, kIsolateSnapshotDataCSymbol)); + isolate_instrs_ = reinterpret_cast( + dlsym(handle_, kIsolateSnapshotInstructionsCSymbol)); + if (vm_data_ == nullptr || vm_instrs_ == nullptr || + isolate_data_ == nullptr || isolate_instrs_ == nullptr) { + FML_LOG(ERROR) << "Failed to load ELF symbols"; + return false; + } + return true; } ElfSnapshot::~ElfSnapshot() { - Dart_UnloadELF(handle_); + dlclose(handle_); } } // namespace dart_utils diff --git a/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.h b/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.h index 41f3bdfcf6765..16ef57130c9b4 100644 --- a/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.h +++ b/engine/src/flutter/shell/platform/fuchsia/runtime/dart/utils/mapped_resource.h @@ -8,7 +8,7 @@ #include #include -#include "third_party/dart/runtime/bin/elf_loader.h" +#include "flutter/fml/unique_fd.h" namespace dart_utils { @@ -33,9 +33,9 @@ class ElfSnapshot { const uint8_t* IsolateInstrs() const { return isolate_instrs_; } private: - bool Load(int fd); + bool Load(const fml::UniqueFD& fd); - Dart_LoadedElf* handle_ = nullptr; + void* handle_ = nullptr; const uint8_t* vm_data_ = nullptr; const uint8_t* vm_instrs_ = nullptr; diff --git a/engine/src/flutter/shell/platform/linux/BUILD.gn b/engine/src/flutter/shell/platform/linux/BUILD.gn index f44abc08c260f..919e807b9261d 100644 --- a/engine/src/flutter/shell/platform/linux/BUILD.gn +++ b/engine/src/flutter/shell/platform/linux/BUILD.gn @@ -107,6 +107,7 @@ source_set("flutter_linux_sources") { "fl_binary_messenger.cc", "fl_compositor.cc", "fl_compositor_opengl.cc", + "fl_compositor_software.cc", "fl_dart_project.cc", "fl_display_monitor.cc", "fl_engine.cc", @@ -215,6 +216,7 @@ executable("flutter_linux_unittests") { "fl_binary_codec_test.cc", "fl_binary_messenger_test.cc", "fl_compositor_opengl_test.cc", + "fl_compositor_software_test.cc", "fl_dart_project_test.cc", "fl_display_monitor_test.cc", "fl_engine_test.cc", diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor.cc b/engine/src/flutter/shell/platform/linux/fl_compositor.cc index a9c9979039903..bff32cf609483 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor.cc +++ b/engine/src/flutter/shell/platform/linux/fl_compositor.cc @@ -12,6 +12,17 @@ static void fl_compositor_class_init(FlCompositorClass* klass) {} static void fl_compositor_init(FlCompositor* self) {} +FlutterRendererType fl_compositor_get_renderer_type(FlCompositor* self) { + g_return_val_if_fail(FL_IS_COMPOSITOR(self), + static_cast(0)); + return FL_COMPOSITOR_GET_CLASS(self)->get_renderer_type(self); +} + +void fl_compositor_setup(FlCompositor* self) { + g_return_if_fail(FL_IS_COMPOSITOR(self)); + FL_COMPOSITOR_GET_CLASS(self)->setup(self); +} + gboolean fl_compositor_create_backing_store( FlCompositor* self, const FlutterBackingStoreConfig* config, diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor.h b/engine/src/flutter/shell/platform/linux/fl_compositor.h index 4e4892433ee38..49ba71aa6757a 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor.h +++ b/engine/src/flutter/shell/platform/linux/fl_compositor.h @@ -16,6 +16,10 @@ G_DECLARE_DERIVABLE_TYPE(FlCompositor, fl_compositor, FL, COMPOSITOR, GObject) struct _FlCompositorClass { GObjectClass parent_class; + FlutterRendererType (*get_renderer_type)(FlCompositor* compositor); + + void (*setup)(FlCompositor* compositor); + gboolean (*create_backing_store)(FlCompositor* compositor, const FlutterBackingStoreConfig* config, FlutterBackingStore* backing_store_out); @@ -39,6 +43,24 @@ struct _FlCompositorClass { * #FlCompositor is an abstract class that implements Flutter compositing. */ +/** + * fl_compositor_get_renderer_type: + * @compositor: an #FlCompositor. + * + * Gets the rendering method this compositor uses. + * + * Returns: a FlutterRendererType. + */ +FlutterRendererType fl_compositor_get_renderer_type(FlCompositor* compositor); + +/** + * fl_compositor_setup: + * @compositor: an #FlCompositor. + * + * Creates resources required before rendering. + */ +void fl_compositor_setup(FlCompositor* compositor); + /** * fl_compositor_create_backing_store: * @compositor: an #FlCompositor. diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc index bf26f51ced608..d27dda8e63599 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.cc @@ -87,16 +87,26 @@ G_DEFINE_TYPE(FlCompositorOpenGL, fl_compositor_opengl, fl_compositor_get_type()) -// Check if running on an NVIDIA driver. -static gboolean is_nvidia() { +// Check if running on driver supporting blit. +static gboolean driver_supports_blit() { const gchar* vendor = reinterpret_cast(glGetString(GL_VENDOR)); - return strstr(vendor, "NVIDIA") != nullptr; -} -// Check if running on an Vivante Corporation driver. -static gboolean is_vivante() { - const gchar* vendor = reinterpret_cast(glGetString(GL_VENDOR)); - return strstr(vendor, "Vivante Corporation") != nullptr; + // Note: List of unsupported vendors due to issue + // https://github.com/flutter/flutter/issues/152099 + const char* unsupported_vendors_exact[] = {"Vivante Corporation", "ARM"}; + const char* unsupported_vendors_fuzzy[] = {"NVIDIA"}; + + for (const char* unsupported : unsupported_vendors_fuzzy) { + if (strstr(vendor, unsupported) != nullptr) { + return FALSE; + } + } + for (const char* unsupported : unsupported_vendors_exact) { + if (strcmp(vendor, unsupported) == 0) { + return FALSE; + } + } + return TRUE; } // Returns the log for the given OpenGL shader. Must be freed by the caller. @@ -435,6 +445,26 @@ static void present_layers_task_cb(gpointer user_data) { g_cond_signal(&self->present_condition); } +static FlutterRendererType fl_compositor_opengl_get_renderer_type( + FlCompositor* compositor) { + return kOpenGL; +} + +static void fl_compositor_opengl_setup(FlCompositor* compositor) { + FlCompositorOpenGL* self = FL_COMPOSITOR_OPENGL(compositor); + + fl_opengl_manager_make_current(self->opengl_manager); + + self->has_gl_framebuffer_blit = + driver_supports_blit() && + (epoxy_gl_version() >= 30 || + epoxy_has_gl_extension("GL_EXT_framebuffer_blit")); + + if (!self->has_gl_framebuffer_blit) { + setup_shader(self); + } +} + static gboolean fl_compositor_opengl_create_backing_store( FlCompositor* compositor, const FlutterBackingStoreConfig* config, @@ -548,6 +578,9 @@ static void fl_compositor_opengl_dispose(GObject* object) { } static void fl_compositor_opengl_class_init(FlCompositorOpenGLClass* klass) { + FL_COMPOSITOR_CLASS(klass)->get_renderer_type = + fl_compositor_opengl_get_renderer_type; + FL_COMPOSITOR_CLASS(klass)->setup = fl_compositor_opengl_setup; FL_COMPOSITOR_CLASS(klass)->create_backing_store = fl_compositor_opengl_create_backing_store; FL_COMPOSITOR_CLASS(klass)->collect_backing_store = @@ -579,21 +612,6 @@ FlCompositorOpenGL* fl_compositor_opengl_new(FlEngine* engine) { return self; } -void fl_compositor_opengl_setup(FlCompositorOpenGL* self) { - g_return_if_fail(FL_IS_COMPOSITOR_OPENGL(self)); - - // Note: NVIDIA and Vivante are temporarily disabled due to - // https://github.com/flutter/flutter/issues/152099 - self->has_gl_framebuffer_blit = - !is_nvidia() && !is_vivante() && - (epoxy_gl_version() >= 30 || - epoxy_has_gl_extension("GL_EXT_framebuffer_blit")); - - if (!self->has_gl_framebuffer_blit) { - setup_shader(self); - } -} - void fl_compositor_opengl_render(FlCompositorOpenGL* self, FlutterViewId view_id, int width, diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.h b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.h index aeead556606bb..9f17bd333eb94 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.h +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl.h @@ -22,7 +22,7 @@ G_DECLARE_FINAL_TYPE(FlCompositorOpenGL, /** * FlCompositorOpenGL: * - * #FlCompositorOpenGL is an abstract class that allows Flutter to draw pixels. + * #FlCompositorOpenGL is class that implements compositing using OpenGL. */ /** @@ -35,15 +35,6 @@ G_DECLARE_FINAL_TYPE(FlCompositorOpenGL, */ FlCompositorOpenGL* fl_compositor_opengl_new(FlEngine* engine); -/** - * fl_compositor_opengl_setup: - * @compositor: an #FlCompositorOpenGL. - * - * Creates OpenGL resources required before rendering. Requires an active - * context. - */ -void fl_compositor_opengl_setup(FlCompositorOpenGL* compositor); - /** * fl_compositor_opengl_render: * @compositor: an #FlCompositorOpenGL. diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc index 0dba8acd3a89e..062e16f1ebb28 100644 --- a/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_opengl_test.cc @@ -30,7 +30,7 @@ TEST(FlCompositorOpenGLTest, BackgroundColor) { g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), 1024, 1024); FlutterBackingStoreConfig config = { @@ -145,7 +145,7 @@ TEST(FlCompositorOpenGLTest, BlitFramebuffer) { g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), 1024, 1024); FlutterBackingStoreConfig config = { @@ -202,7 +202,7 @@ TEST(FlCompositorOpenGLTest, BlitFramebufferExtension) { g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), 1024, 1024); FlutterBackingStoreConfig config = { @@ -252,7 +252,7 @@ TEST(FlCompositorOpenGLTest, NoBlitFramebuffer) { g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), 1024, 1024); FlutterBackingStoreConfig config = { @@ -305,7 +305,7 @@ TEST(FlCompositorOpenGLTest, BlitFramebufferNvidia) { g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); fl_compositor_wait_for_frame(FL_COMPOSITOR(compositor), 1024, 1024); FlutterBackingStoreConfig config = { @@ -359,7 +359,7 @@ TEST(FlCompositorOpenGLTest, MultiView) { g_autoptr(FlMockRenderable) secondary_renderable = fl_mock_renderable_new(); g_autoptr(FlCompositorOpenGL) compositor = fl_compositor_opengl_new(engine); - fl_compositor_opengl_setup(compositor); + fl_compositor_setup(FL_COMPOSITOR(compositor)); fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); FlutterViewId view_id = fl_engine_add_view(engine, FL_RENDERABLE(secondary_renderable), 1024, 768, diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_software.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_software.cc new file mode 100644 index 0000000000000..9600bb0367343 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_software.cc @@ -0,0 +1,188 @@ +// Copyright 2013 The Flutter 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 "fl_compositor_software.h" + +#include "flutter/shell/platform/linux/fl_engine_private.h" + +struct _FlCompositorSoftware { + FlCompositor parent_instance; + + // Engine we are rendering. + GWeakRef engine; + + // Surfaces to draw on each view. + GHashTable* surfaces_by_view_id; + + // Control thread access to the frame. + GMutex frame_mutex; +}; + +G_DEFINE_TYPE(FlCompositorSoftware, + fl_compositor_software, + fl_compositor_get_type()) + +static FlutterRendererType fl_compositor_software_get_renderer_type( + FlCompositor* compositor) { + return kSoftware; +} + +static void fl_compositor_software_setup(FlCompositor* compositor) { + // No special work required. +} + +static gboolean fl_compositor_software_create_backing_store( + FlCompositor* compositor, + const FlutterBackingStoreConfig* config, + FlutterBackingStore* backing_store_out) { + size_t allocation_length = config->size.width * config->size.height * 4; + uint8_t* allocation = static_cast(malloc(allocation_length)); + if (allocation == nullptr) { + return FALSE; + } + + backing_store_out->type = kFlutterBackingStoreTypeSoftware; + backing_store_out->software.allocation = allocation; + backing_store_out->software.height = config->size.height; + backing_store_out->software.row_bytes = config->size.width * 4; + backing_store_out->software.user_data = nullptr; + backing_store_out->software.destruction_callback = [](void* p) { + // Backing store destroyed in + // fl_compositor_software_collect_backing_store(), set on + // FlutterCompositor.collect_backing_store_callback during engine start. + }; + + return TRUE; +} + +static gboolean fl_compositor_software_collect_backing_store( + FlCompositor* compositor, + const FlutterBackingStore* backing_store) { + free(const_cast(backing_store->software.allocation)); + + return TRUE; +} + +static void fl_compositor_software_wait_for_frame(FlCompositor* compositor, + int target_width, + int target_height) {} + +static gboolean fl_compositor_software_present_layers( + FlCompositor* compositor, + FlutterViewId view_id, + const FlutterLayer** layers, + size_t layers_count) { + FlCompositorSoftware* self = FL_COMPOSITOR_SOFTWARE(compositor); + + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->frame_mutex); + + // TODO(robert-ancell): Support multiple layers + if (layers_count == 1) { + const FlutterLayer* layer = layers[0]; + g_assert(layer->type == kFlutterLayerContentTypeBackingStore); + g_assert(layer->backing_store->type == kFlutterBackingStoreTypeSoftware); + const FlutterBackingStore* backing_store = layer->backing_store; + + cairo_surface_t* surface = + reinterpret_cast((g_hash_table_lookup( + self->surfaces_by_view_id, GINT_TO_POINTER(view_id)))); + + size_t allocation_length = + backing_store->software.row_bytes * backing_store->software.height; + unsigned char* old_data = + surface != nullptr ? cairo_image_surface_get_data(surface) : nullptr; + unsigned char* data = + static_cast(realloc(old_data, allocation_length)); + memcpy(data, backing_store->software.allocation, allocation_length); + cairo_surface_t* new_surface = cairo_image_surface_create_for_data( + data, CAIRO_FORMAT_ARGB32, backing_store->software.row_bytes / 4, + backing_store->software.height, backing_store->software.row_bytes); + g_hash_table_insert(self->surfaces_by_view_id, GINT_TO_POINTER(view_id), + new_surface); + } + + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { + return TRUE; + } + g_autoptr(FlRenderable) renderable = + fl_engine_get_renderable(engine, view_id); + if (renderable == nullptr) { + return TRUE; + } + + fl_renderable_redraw(renderable); + + return TRUE; +} + +static void fl_compositor_software_dispose(GObject* object) { + FlCompositorSoftware* self = FL_COMPOSITOR_SOFTWARE(object); + + g_weak_ref_clear(&self->engine); + if (self->surfaces_by_view_id != nullptr) { + GHashTableIter iter; + g_hash_table_iter_init(&iter, self->surfaces_by_view_id); + gpointer value; + while (g_hash_table_iter_next(&iter, nullptr, &value)) { + cairo_surface_t* surface = reinterpret_cast(value); + free(cairo_image_surface_get_data(surface)); + } + } + g_clear_pointer(&self->surfaces_by_view_id, g_hash_table_unref); + + G_OBJECT_CLASS(fl_compositor_software_parent_class)->dispose(object); +} + +static void fl_compositor_software_class_init( + FlCompositorSoftwareClass* klass) { + FL_COMPOSITOR_CLASS(klass)->get_renderer_type = + fl_compositor_software_get_renderer_type; + FL_COMPOSITOR_CLASS(klass)->setup = fl_compositor_software_setup; + FL_COMPOSITOR_CLASS(klass)->create_backing_store = + fl_compositor_software_create_backing_store; + FL_COMPOSITOR_CLASS(klass)->collect_backing_store = + fl_compositor_software_collect_backing_store; + FL_COMPOSITOR_CLASS(klass)->wait_for_frame = + fl_compositor_software_wait_for_frame; + FL_COMPOSITOR_CLASS(klass)->present_layers = + fl_compositor_software_present_layers; + + G_OBJECT_CLASS(klass)->dispose = fl_compositor_software_dispose; +} + +static void fl_compositor_software_init(FlCompositorSoftware* self) { + self->surfaces_by_view_id = g_hash_table_new_full( + g_direct_hash, g_direct_equal, nullptr, + reinterpret_cast(cairo_surface_destroy)); +} + +FlCompositorSoftware* fl_compositor_software_new(FlEngine* engine) { + FlCompositorSoftware* self = FL_COMPOSITOR_SOFTWARE( + g_object_new(fl_compositor_software_get_type(), nullptr)); + + g_weak_ref_init(&self->engine, engine); + + return self; +} + +gboolean fl_compositor_software_render(FlCompositorSoftware* self, + FlutterViewId view_id, + cairo_t* cr, + gint scale_factor) { + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&self->frame_mutex); + + cairo_surface_t* surface = + reinterpret_cast((g_hash_table_lookup( + self->surfaces_by_view_id, GINT_TO_POINTER(view_id)))); + if (surface == nullptr) { + return FALSE; + } + + cairo_surface_set_device_scale(surface, scale_factor, scale_factor); + cairo_set_source_surface(cr, surface, 0.0, 0.0); + cairo_paint(cr); + + return TRUE; +} diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_software.h b/engine/src/flutter/shell/platform/linux/fl_compositor_software.h new file mode 100644 index 0000000000000..a366efdf984bd --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_software.h @@ -0,0 +1,57 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_COMPOSITOR_SOFTWARE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_COMPOSITOR_SOFTWARE_H_ + +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/fl_compositor.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlCompositorSoftware, + fl_compositor_software, + FL, + COMPOSITOR_SOFTWARE, + FlCompositor) + +/** + * FlCompositorSoftware: + * + * #FlCompositorSoftware is a class that implements compositing using software + * rendering. + */ + +/** + * fl_compositor_software_new: + * @engine: an #FlEngine. + * + * Creates a new software rendering compositor. + * + * Returns: a new #FlCompositorSoftware. + */ +FlCompositorSoftware* fl_compositor_software_new(FlEngine* engine); + +/** + * fl_compositor_software_render: + * @compositor: an #FlCompositorSoftware. + * @view_id: the view to render. + * @cr: the cairo context to draw to. + * @scale_factor: pixel scale factor. + * + * Render the current frame. + * + * Returns: TRUE if rendered. + */ +gboolean fl_compositor_software_render(FlCompositorSoftware* compositor, + FlutterViewId view_id, + cairo_t* cr, + gint scale_factor); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_COMPOSITOR_SOFTWARE_H_ diff --git a/engine/src/flutter/shell/platform/linux/fl_compositor_software_test.cc b/engine/src/flutter/shell/platform/linux/fl_compositor_software_test.cc new file mode 100644 index 0000000000000..58b34824f13f1 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_compositor_software_test.cc @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter 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 "gtest/gtest.h" + +#include "flutter/common/constants.h" +#include "flutter/shell/platform/linux/fl_compositor_software.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/testing/mock_renderable.h" + +TEST(FlCompositorSoftwareTest, Render) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + + g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new(); + g_autoptr(FlCompositorSoftware) compositor = + fl_compositor_software_new(engine); + fl_engine_set_implicit_view(engine, FL_RENDERABLE(renderable)); + FlutterBackingStoreConfig config = { + .struct_size = sizeof(FlutterBackingStoreConfig), + .size = {.width = 1024, .height = 1024}}; + FlutterBackingStore backing_store; + fl_compositor_create_backing_store(FL_COMPOSITOR(compositor), &config, + &backing_store); + + const FlutterLayer layer0 = {.struct_size = sizeof(FlutterLayer), + .type = kFlutterLayerContentTypeBackingStore, + .backing_store = &backing_store, + .size = {.width = 1024, .height = 1024}}; + const FlutterLayer* layers[] = {&layer0}; + + unsigned char image_data[1024 * 1024 * 4]; + cairo_surface_t* surface = cairo_image_surface_create_for_data( + image_data, CAIRO_FORMAT_ARGB32, 1024, 1024, 1024 * 4); + cairo_t* cr = cairo_create(surface); + fl_compositor_present_layers(FL_COMPOSITOR(compositor), + flutter::kFlutterImplicitViewId, layers, 1); + fl_compositor_software_render(compositor, flutter::kFlutterImplicitViewId, cr, + 1); + cairo_surface_destroy(surface); +} diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 2d82431c5dfaa..ac6b865453cc0 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc @@ -14,6 +14,7 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_compositor_opengl.h" +#include "flutter/shell/platform/linux/fl_compositor_software.h" #include "flutter/shell/platform/linux/fl_dart_project_private.h" #include "flutter/shell/platform/linux/fl_display_monitor.h" #include "flutter/shell/platform/linux/fl_engine_private.h" @@ -296,12 +297,6 @@ static uint32_t fl_engine_gl_get_fbo(void* user_data) { return 0; } -static bool fl_engine_gl_present(void* user_data) { - // No action required, as this is handled in - // compositor_present_view_callback. - return true; -} - static bool fl_engine_gl_make_resource_current(void* user_data) { FlEngine* self = static_cast(user_data); fl_opengl_manager_make_resource_current(self->opengl_manager); @@ -560,7 +555,21 @@ static FlEngine* fl_engine_new_full(FlDartProject* project, FlEngine* self = FL_ENGINE(g_object_new(fl_engine_get_type(), nullptr)); self->project = FL_DART_PROJECT(g_object_ref(project)); - self->compositor = FL_COMPOSITOR(fl_compositor_opengl_new(self)); + const gchar* renderer = g_getenv("FLUTTER_LINUX_RENDERER"); + if (g_strcmp0(renderer, "software") == 0) { + self->compositor = FL_COMPOSITOR(fl_compositor_software_new(self)); + g_warning( + "Using the software renderer. Not all features are supported. This is " + "not recommended.\n" + "\n" + "To switch back to the default renderer, unset the " + "FLUTTER_LINUX_RENDERER environment variable."); + } else { + if (renderer != nullptr && strcmp(renderer, "opengl") != 0) { + g_warning("Unknown renderer type '%s', defaulting to opengl", renderer); + } + self->compositor = FL_COMPOSITOR(fl_compositor_opengl_new(self)); + } if (binary_messenger != nullptr) { self->binary_messenger = FL_BINARY_MESSENGER(g_object_ref(binary_messenger)); @@ -614,16 +623,36 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); FlutterRendererConfig config = {}; - config.type = kOpenGL; - config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); - config.open_gl.gl_proc_resolver = fl_engine_gl_proc_resolver; - config.open_gl.make_current = fl_engine_gl_make_current; - config.open_gl.clear_current = fl_engine_gl_clear_current; - config.open_gl.fbo_callback = fl_engine_gl_get_fbo; - config.open_gl.present = fl_engine_gl_present; - config.open_gl.make_resource_current = fl_engine_gl_make_resource_current; - config.open_gl.gl_external_texture_frame_callback = - fl_engine_gl_external_texture_frame_callback; + config.type = fl_compositor_get_renderer_type(self->compositor); + switch (config.type) { + case kSoftware: + config.software.struct_size = sizeof(FlutterSoftwareRendererConfig); + // No action required, as this is handled in + // compositor_present_view_callback. + config.software.surface_present_callback = + [](void* user_data, const void* allocation, size_t row_bytes, + size_t height) { return true; }; + break; + case kOpenGL: + config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); + config.open_gl.gl_proc_resolver = fl_engine_gl_proc_resolver; + config.open_gl.make_current = fl_engine_gl_make_current; + config.open_gl.clear_current = fl_engine_gl_clear_current; + config.open_gl.fbo_callback = fl_engine_gl_get_fbo; + // No action required, as this is handled in + // compositor_present_view_callback. + config.open_gl.present = [](void* user_data) { return true; }; + config.open_gl.make_resource_current = fl_engine_gl_make_resource_current; + config.open_gl.gl_external_texture_frame_callback = + fl_engine_gl_external_texture_frame_callback; + break; + case kMetal: + case kVulkan: + default: + g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, + "Unsupported renderer type"); + return FALSE; + } FlutterTaskRunnerDescription platform_task_runner = {}; platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); diff --git a/engine/src/flutter/shell/platform/linux/fl_view.cc b/engine/src/flutter/shell/platform/linux/fl_view.cc index 8e3a9a7c86a03..1a8a7f1333904 100644 --- a/engine/src/flutter/shell/platform/linux/fl_view.cc +++ b/engine/src/flutter/shell/platform/linux/fl_view.cc @@ -12,6 +12,7 @@ #include "flutter/common/constants.h" #include "flutter/shell/platform/linux/fl_accessible_node.h" #include "flutter/shell/platform/linux/fl_compositor_opengl.h" +#include "flutter/shell/platform/linux/fl_compositor_software.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/fl_opengl_manager.h" @@ -29,8 +30,11 @@ struct _FlView { GtkBox parent_instance; - // The widget rendering the Flutter view. - GtkGLArea* gl_area; + // Event box the render area goes inside. + GtkWidget* event_box; + + // The widget rendering the Flutter view, either GtkGLArea or GtkDrawingArea. + GtkWidget* render_area; // Engine this view is showing. FlEngine* engine; @@ -245,7 +249,7 @@ static void on_pre_engine_restart_cb(FlView* self) { static void fl_view_redraw(FlRenderable* renderable) { FlView* self = FL_VIEW(renderable); - gtk_widget_queue_draw(GTK_WIDGET(self->gl_area)); + gtk_widget_queue_draw(self->render_area); if (!self->have_first_frame) { self->have_first_frame = TRUE; @@ -258,7 +262,7 @@ static void fl_view_redraw(FlRenderable* renderable) { // Implements FlRenderable::make_current static void fl_view_make_current(FlRenderable* renderable) { FlView* self = FL_VIEW(renderable); - gtk_gl_area_make_current(self->gl_area); + gtk_gl_area_make_current(GTK_GL_AREA(self->render_area)); } // Implements FlPluginRegistry::get_registrar_for_plugin. @@ -438,15 +442,12 @@ static void gesture_zoom_end_cb(FlView* self) { } static GdkGLContext* create_context_cb(FlView* self) { - init_scrolling(self); - init_touch(self); - FlOpenGLManager* opengl_manager = fl_engine_get_opengl_manager(self->engine); g_autoptr(GError) error = nullptr; if (!fl_opengl_manager_create_contexts( opengl_manager, gtk_widget_get_parent_window(GTK_WIDGET(self)), &error)) { - gtk_gl_area_set_error(self->gl_area, error); + gtk_gl_area_set_error(GTK_GL_AREA(self->render_area), error); return nullptr; } @@ -455,18 +456,7 @@ static GdkGLContext* create_context_cb(FlView* self) { } static void realize_cb(FlView* self) { - g_autoptr(GError) error = nullptr; - - fl_opengl_manager_make_current(fl_engine_get_opengl_manager(self->engine)); - - GError* gl_error = gtk_gl_area_get_error(self->gl_area); - if (gl_error != NULL) { - g_warning("Failed to initialize GLArea: %s", gl_error->message); - return; - } - - fl_compositor_opengl_setup( - FL_COMPOSITOR_OPENGL(fl_engine_get_compositor(self->engine))); + fl_compositor_setup(fl_engine_get_compositor(self->engine)); GtkWidget* toplevel_window = gtk_widget_get_toplevel(GTK_WIDGET(self)); @@ -482,6 +472,7 @@ static void realize_cb(FlView* self) { // during initialization. fl_opengl_manager_clear_current(fl_engine_get_opengl_manager(self->engine)); + g_autoptr(GError) error = nullptr; if (!fl_engine_start(self->engine, &error)) { g_warning("Failed to start Flutter engine: %s", error->message); return; @@ -497,13 +488,13 @@ static void secondary_realize_cb(FlView* self) { } static gboolean render_cb(FlView* self, GdkGLContext* context) { - if (gtk_gl_area_get_error(self->gl_area) != NULL) { + if (gtk_gl_area_get_error(GTK_GL_AREA(self->render_area)) != NULL) { return FALSE; } - int width = gtk_widget_get_allocated_width(GTK_WIDGET(self->gl_area)); - int height = gtk_widget_get_allocated_height(GTK_WIDGET(self->gl_area)); - gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self->gl_area)); + int width = gtk_widget_get_allocated_width(self->render_area); + int height = gtk_widget_get_allocated_height(self->render_area); + gint scale_factor = gtk_widget_get_scale_factor(self->render_area); fl_compositor_opengl_render( FL_COMPOSITOR_OPENGL(fl_engine_get_compositor(self->engine)), self->view_id, width * scale_factor, height * scale_factor, @@ -512,12 +503,18 @@ static gboolean render_cb(FlView* self, GdkGLContext* context) { return TRUE; } +static gboolean draw_cb(FlView* self, cairo_t* cr) { + return fl_compositor_software_render( + FL_COMPOSITOR_SOFTWARE(fl_engine_get_compositor(self->engine)), + self->view_id, cr, gtk_widget_get_scale_factor(GTK_WIDGET(self))); +} + static void unrealize_cb(FlView* self) { g_autoptr(GError) error = nullptr; fl_opengl_manager_make_current(fl_engine_get_opengl_manager(self->engine)); - GError* gl_error = gtk_gl_area_get_error(self->gl_area); + GError* gl_error = gtk_gl_area_get_error(GTK_GL_AREA(self->render_area)); if (gl_error != NULL) { g_warning("Failed to uninitialize GLArea: %s", gl_error->message); return; @@ -591,7 +588,7 @@ static void fl_view_realize(GtkWidget* widget) { GTK_WIDGET_CLASS(fl_view_parent_class)->realize(widget); // Realize the child widgets. - gtk_widget_realize(GTK_WIDGET(self->gl_area)); + gtk_widget_realize(self->render_area); } static gboolean handle_key_event(FlView* self, GdkEventKey* key_event) { @@ -674,6 +671,34 @@ static void fl_view_class_init(FlViewClass* klass) { // Engine related construction. static void setup_engine(FlView* self) { + FlutterRendererType renderer_type = + fl_compositor_get_renderer_type(fl_engine_get_compositor(self->engine)); + switch (renderer_type) { + case kOpenGL: + self->render_area = gtk_gl_area_new(); + gtk_gl_area_set_has_alpha(GTK_GL_AREA(self->render_area), TRUE); + g_signal_connect_swapped(self->render_area, "render", + G_CALLBACK(render_cb), self); + g_signal_connect_swapped(self->render_area, "create-context", + G_CALLBACK(create_context_cb), self); + g_signal_connect_swapped(self->render_area, "unrealize", + G_CALLBACK(unrealize_cb), self); + break; + case kSoftware: + self->render_area = gtk_drawing_area_new(); + g_signal_connect_swapped(self->render_area, "draw", G_CALLBACK(draw_cb), + self); + break; + default: + self->render_area = gtk_label_new("Unsupported Flutter renderer type"); + break; + } + + gtk_widget_show(self->render_area); + gtk_container_add(GTK_CONTAINER(self->event_box), self->render_area); + g_signal_connect_swapped(self->render_area, "realize", G_CALLBACK(realize_cb), + self); + self->view_accessible = fl_view_accessible_new(self->engine, self->view_id); fl_socket_accessible_embed( FL_SOCKET_ACCESSIBLE(gtk_widget_get_accessible(GTK_WIDGET(self))), @@ -681,6 +706,9 @@ static void setup_engine(FlView* self) { self->pointer_manager = fl_pointer_manager_new(self->view_id, self->engine); + init_scrolling(self); + init_touch(self); + self->on_pre_engine_restart_cb_id = g_signal_connect_swapped(self->engine, "on-pre-engine-restart", G_CALLBACK(on_pre_engine_restart_cb), self); @@ -699,50 +727,43 @@ static void fl_view_init(FlView* self) { .red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0}; self->background_color = gdk_rgba_copy(&default_background); - GtkWidget* event_box = gtk_event_box_new(); - gtk_widget_set_hexpand(event_box, TRUE); - gtk_widget_set_vexpand(event_box, TRUE); - gtk_container_add(GTK_CONTAINER(self), event_box); - gtk_widget_show(event_box); - gtk_widget_add_events(event_box, + self->event_box = gtk_event_box_new(); + gtk_widget_set_hexpand(self->event_box, TRUE); + gtk_widget_set_vexpand(self->event_box, TRUE); + gtk_container_add(GTK_CONTAINER(self), self->event_box); + gtk_widget_show(self->event_box); + gtk_widget_add_events(self->event_box, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK); - g_signal_connect_swapped(event_box, "button-press-event", + g_signal_connect_swapped(self->event_box, "button-press-event", G_CALLBACK(button_press_event_cb), self); - g_signal_connect_swapped(event_box, "button-release-event", + g_signal_connect_swapped(self->event_box, "button-release-event", G_CALLBACK(button_release_event_cb), self); - g_signal_connect_swapped(event_box, "scroll-event", + g_signal_connect_swapped(self->event_box, "scroll-event", G_CALLBACK(scroll_event_cb), self); - g_signal_connect_swapped(event_box, "motion-notify-event", + g_signal_connect_swapped(self->event_box, "motion-notify-event", G_CALLBACK(motion_notify_event_cb), self); - g_signal_connect_swapped(event_box, "enter-notify-event", + g_signal_connect_swapped(self->event_box, "enter-notify-event", G_CALLBACK(enter_notify_event_cb), self); - g_signal_connect_swapped(event_box, "leave-notify-event", + g_signal_connect_swapped(self->event_box, "leave-notify-event", G_CALLBACK(leave_notify_event_cb), self); - GtkGesture* zoom = gtk_gesture_zoom_new(event_box); + GtkGesture* zoom = gtk_gesture_zoom_new(self->event_box); g_signal_connect_swapped(zoom, "begin", G_CALLBACK(gesture_zoom_begin_cb), self); g_signal_connect_swapped(zoom, "scale-changed", G_CALLBACK(gesture_zoom_update_cb), self); g_signal_connect_swapped(zoom, "end", G_CALLBACK(gesture_zoom_end_cb), self); - GtkGesture* rotate = gtk_gesture_rotate_new(event_box); + GtkGesture* rotate = gtk_gesture_rotate_new(self->event_box); g_signal_connect_swapped(rotate, "begin", G_CALLBACK(gesture_rotation_begin_cb), self); g_signal_connect_swapped(rotate, "angle-changed", G_CALLBACK(gesture_rotation_update_cb), self); g_signal_connect_swapped(rotate, "end", G_CALLBACK(gesture_rotation_end_cb), self); - g_signal_connect_swapped(event_box, "touch-event", G_CALLBACK(touch_event_cb), - self); - - self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); - gtk_gl_area_set_has_alpha(self->gl_area, TRUE); - gtk_widget_show(GTK_WIDGET(self->gl_area)); - gtk_container_add(GTK_CONTAINER(event_box), GTK_WIDGET(self->gl_area)); - g_signal_connect_swapped(self->gl_area, "render", G_CALLBACK(render_cb), - self); + g_signal_connect_swapped(self->event_box, "touch-event", + G_CALLBACK(touch_event_cb), self); g_signal_connect_swapped(self, "size-allocate", G_CALLBACK(size_allocate_cb), self); @@ -757,13 +778,6 @@ G_MODULE_EXPORT FlView* fl_view_new(FlDartProject* project) { setup_engine(self); - g_signal_connect_swapped(self->gl_area, "create-context", - G_CALLBACK(create_context_cb), self); - g_signal_connect_swapped(self->gl_area, "realize", G_CALLBACK(realize_cb), - self); - g_signal_connect_swapped(self->gl_area, "unrealize", G_CALLBACK(unrealize_cb), - self); - fl_engine_set_implicit_view(engine, FL_RENDERABLE(self)); return self; @@ -779,7 +793,7 @@ G_MODULE_EXPORT FlView* fl_view_new_for_engine(FlEngine* engine) { setup_engine(self); - g_signal_connect_swapped(self->gl_area, "realize", + g_signal_connect_swapped(self->render_area, "realize", G_CALLBACK(secondary_realize_cb), self); return self; } diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc index 3a5c7a65f6a8f..d37d39cd9aed4 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_gtk.cc @@ -128,6 +128,8 @@ void gtk_window_deiconify(GtkWindow* window) { mock->gtk_window_deiconify(window); } +void gtk_widget_realize(GtkWidget* widget) {} + void gtk_widget_show(GtkWidget* widget) {} void gtk_widget_destroy(GtkWidget* widget) { diff --git a/engine/src/flutter/shell/platform/windows/fixtures/main.dart b/engine/src/flutter/shell/platform/windows/fixtures/main.dart index a9d341cee0539..b811fab5b03b8 100644 --- a/engine/src/flutter/shell/platform/windows/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/windows/fixtures/main.dart @@ -446,8 +446,6 @@ Future sendSemanticsTreeInfo() async { scrollExtentMax: 0, scrollExtentMin: 0, rect: const ui.Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: 'identifier', label: 'label', labelAttributes: const [], diff --git a/engine/src/flutter/skia/BUILD.gn b/engine/src/flutter/skia/BUILD.gn index bb4d1edef5401..522d2f42ad977 100644 --- a/engine/src/flutter/skia/BUILD.gn +++ b/engine/src/flutter/skia/BUILD.gn @@ -66,6 +66,10 @@ config("skia_public") { if (is_mac || is_ios) { cflags_objcc += [ "-Wno-unguarded-availability" ] } + + if (is_qnx) { + defines += [ "SKRP_CPU_SCALAR" ] + } } # Skia internal APIs, used by Skia itself and a few test tools. @@ -712,7 +716,9 @@ skia_component("skia") { } } else { sources += [ "$_skia_root/src/ports/SkOSFile_posix.cpp" ] - libs += [ "dl" ] + if (!is_qnx) { + libs += [ "dl" ] + } } if (is_android) { @@ -725,7 +731,7 @@ skia_component("skia") { ] } - if (is_linux || is_wasm) { + if (is_linux || is_wasm || is_qnx) { sources += [ "$_skia_root/src/ports/SkDebug_stdio.cpp" ] if (skia_use_egl) { libs += [ "GLESv2" ] diff --git a/engine/src/flutter/sky/packages/sky_engine/LICENSE b/engine/src/flutter/sky/packages/sky_engine/LICENSE index 930b44d807888..8bcb6fb958896 100644 --- a/engine/src/flutter/sky/packages/sky_engine/LICENSE +++ b/engine/src/flutter/sky/packages/sky_engine/LICENSE @@ -17140,11 +17140,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2000-2005 Fred L. Drake, Jr. Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Cristian Rodríguez Copyright (c) 2016 Thomas Beutlich Copyright (c) 2017 Rhodri James Copyright (c) 2022 Thijs Schreijer +Copyright (c) 2023 Hanno Böck +Copyright (c) 2023 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -17176,7 +17179,7 @@ Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie Copyright (c) 2016 Eric Rahm -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Gaurav Copyright (c) 2016 Thomas Beutlich Copyright (c) 2016 Gustavo Grieco @@ -17195,10 +17198,15 @@ Copyright (c) 2018 Mariusz Zaborski Copyright (c) 2019 David Loffredo Copyright (c) 2019-2020 Ben Wagner Copyright (c) 2019 Vadim Zeitlin -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton Copyright (c) 2022 Jann Horn +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Owain Davies +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024-2025 Berkay Eren Ürün +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -17259,7 +17267,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Don Lewis Copyright (c) 2017 Rhodri James @@ -17267,8 +17275,10 @@ Copyright (c) 2017 Alexander Bluhm Copyright (c) 2017 Benbuck Nason Copyright (c) 2017 José Gutiérrez de la Concha Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Hanno Böck Licensed under the MIT license: @@ -17298,13 +17308,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2004-2009 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo Copyright (c) 2020 Joe Orton Copyright (c) 2020 Kleber Tarcísio Copyright (c) 2021 Tim Bray Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride Licensed under the MIT license: @@ -17336,6 +17347,8 @@ Copyright (c) 2002-2009 Karl Waclawek Copyright (c) 2016-2017 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2017 Franek Korta +Copyright (c) 2022 Sean McBride +Copyright (c) 2025 Hanno Böck Licensed under the MIT license: @@ -17364,7 +17377,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2002-2005 Karl Waclawek -Copyright (c) 2016-2017 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2017 Rhodri James Licensed under the MIT license: @@ -17429,7 +17442,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2005 Karl Waclawek -Copyright (c) 2016-2019 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Licensed under the MIT license: @@ -17541,6 +17554,34 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- expat +Copyright (c) 1997-2000 Thai Open Source Software Center Ltd +Copyright (c) 2000 Clark Cooper +Copyright (c) 2002 Fred L. Drake, Jr. +Copyright (c) 2016-2024 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- +expat + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. @@ -17605,10 +17646,10 @@ Copyright (c) 2002 Greg Stein Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Licensed under the MIT license: @@ -17637,7 +17678,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Karl Waclawek Copyright (c) 2002 Fred L. Drake, Jr. -Copyright (c) 2017 Sebastian Pipping +Copyright (c) 2017-2024 Sebastian Pipping Licensed under the MIT license: @@ -17667,10 +17708,11 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2004-2006 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -17970,7 +18012,7 @@ authorization of the copyright holder. expat Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -18091,7 +18133,8 @@ expat Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Greg Stein Copyright (c) 2005 Karl Waclawek -Copyright (c) 2017-2021 Sebastian Pipping +Copyright (c) 2017-2023 Sebastian Pipping +Copyright (c) 2023 Orgad Shaneh Licensed under the MIT license: @@ -18617,9 +18660,11 @@ expat Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -22519,6 +22564,32 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- +expat + +Copyright (c) 2022 Mark Brand +Copyright (c) 2025 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- pkg Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file @@ -30447,7 +30518,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/6aeb798bdbe27e6e6c5ee533dca392404ca496ce +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/239174405ad089da5f6063c8c002efbbd354b0b0 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- diff --git a/engine/src/flutter/testing/dart/BUILD.gn b/engine/src/flutter/testing/dart/BUILD.gn index d240383f48976..f901ae512bdfd 100644 --- a/engine/src/flutter/testing/dart/BUILD.gn +++ b/engine/src/flutter/testing/dart/BUILD.gn @@ -72,7 +72,7 @@ foreach(test, tests) { group("dart") { testonly = true - deps = [ "//flutter/testing/dart/observatory" ] + deps = [ "//flutter/testing/dart/vm_service" ] foreach(test, tests) { deps += [ ":compile_$test" ] } diff --git a/engine/src/flutter/testing/dart/observatory/BUILD.gn b/engine/src/flutter/testing/dart/vm_service/BUILD.gn similarity index 96% rename from engine/src/flutter/testing/dart/observatory/BUILD.gn rename to engine/src/flutter/testing/dart/vm_service/BUILD.gn index 780b3f7d36860..aade578f11682 100644 --- a/engine/src/flutter/testing/dart/observatory/BUILD.gn +++ b/engine/src/flutter/testing/dart/vm_service/BUILD.gn @@ -18,7 +18,7 @@ foreach(test, tests) { } } -group("observatory") { +group("vm_service") { testonly = true deps = [] foreach(test, tests) { diff --git a/engine/src/flutter/testing/dart/observatory/README.md b/engine/src/flutter/testing/dart/vm_service/README.md similarity index 100% rename from engine/src/flutter/testing/dart/observatory/README.md rename to engine/src/flutter/testing/dart/vm_service/README.md diff --git a/engine/src/flutter/testing/dart/observatory/shader_reload_test.dart b/engine/src/flutter/testing/dart/vm_service/shader_reload_test.dart similarity index 100% rename from engine/src/flutter/testing/dart/observatory/shader_reload_test.dart rename to engine/src/flutter/testing/dart/vm_service/shader_reload_test.dart diff --git a/engine/src/flutter/testing/dart/observatory/skp_test.dart b/engine/src/flutter/testing/dart/vm_service/skp_test.dart similarity index 100% rename from engine/src/flutter/testing/dart/observatory/skp_test.dart rename to engine/src/flutter/testing/dart/vm_service/skp_test.dart diff --git a/engine/src/flutter/testing/dart/observatory/tracing_test.dart b/engine/src/flutter/testing/dart/vm_service/tracing_test.dart similarity index 100% rename from engine/src/flutter/testing/dart/observatory/tracing_test.dart rename to engine/src/flutter/testing/dart/vm_service/tracing_test.dart diff --git a/engine/src/flutter/testing/dart/observatory/vmservice_methods_test.dart b/engine/src/flutter/testing/dart/vm_service/vmservice_methods_test.dart similarity index 100% rename from engine/src/flutter/testing/dart/observatory/vmservice_methods_test.dart rename to engine/src/flutter/testing/dart/vm_service/vmservice_methods_test.dart diff --git a/engine/src/flutter/testing/display_list_testing.cc b/engine/src/flutter/testing/display_list_testing.cc index 16904144a1701..5af0ecabffa1a 100644 --- a/engine/src/flutter/testing/display_list_testing.cc +++ b/engine/src/flutter/testing/display_list_testing.cc @@ -8,6 +8,7 @@ #include #include "flutter/display_list/display_list.h" +#include "flutter/display_list/dl_canvas.h" #include "flutter/display_list/effects/dl_color_filters.h" #include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h index 530b65ecb9a5d..fc05d29e64d89 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h @@ -7,6 +7,7 @@ #import +@class FlutterEngine; @protocol FlutterPluginRegistrant; @interface AppDelegate : UIResponder @@ -16,6 +17,11 @@ // A mirror of the FlutterAppDelegate API for integration testing. @property(nonatomic, strong, nullable) NSObject* pluginRegistrant; +/** The FlutterEngine that will be served by `takeLaunchEngine`. */ +@property(nonatomic, strong, nullable) FlutterEngine* mockLaunchEngine; + +- (nullable FlutterEngine*)takeLaunchEngine; + @end #endif // FLUTTER_TESTING_IOS_IOSUNITTESTS_APP_APPDELEGATE_H_ diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m index 9e22f24ef0b8a..5d468d47102ca 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m @@ -30,4 +30,9 @@ - (void)applicationDidBecomeActive:(UIApplication*)application { - (void)applicationWillTerminate:(UIApplication*)application { } +- (FlutterEngine*)takeLaunchEngine { + // This is just served up for tests and doesn't actually take ownership. + return _mockLaunchEngine; +} + @end diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard b/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard new file mode 100644 index 0000000000000..a6eaed8523310 --- /dev/null +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj b/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj index 1bec57693f4b1..0b593d58ad1d2 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj +++ b/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 0D1CE5D8233430F400E5D880 /* FlutterChannelsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1CE5D7233430F400E5D880 /* FlutterChannelsTest.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 0D48E9ED2DCE7B16005474A1 /* Flutter.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */; }; + 0D48E9EE2DCE7B16005474A1 /* Flutter.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */; }; 0D6AB6B622BB05E100EEE540 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6AB6B522BB05E100EEE540 /* AppDelegate.m */; }; 0D6AB6B922BB05E100EEE540 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6AB6B822BB05E100EEE540 /* ViewController.m */; }; 0D6AB6BC22BB05E100EEE540 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D6AB6BA22BB05E100EEE540 /* Main.storyboard */; }; @@ -55,6 +57,7 @@ 0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterPluginAppLifeCycleDelegateTest.mm; sourceTree = ""; }; 0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest.mm; sourceTree = ""; }; 0D1CE5D7233430F400E5D880 /* FlutterChannelsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterChannelsTest.m; sourceTree = ""; }; + 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Flutter.storyboard; sourceTree = ""; }; 0D6AB6B122BB05E100EEE540 /* IosUnitTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IosUnitTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D6AB6B422BB05E100EEE540 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 0D6AB6B522BB05E100EEE540 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -162,6 +165,7 @@ 0D6AB6BF22BB05E200EEE540 /* LaunchScreen.storyboard */, 0D6AB6C222BB05E200EEE540 /* Info.plist */, 0D6AB6C322BB05E200EEE540 /* main.m */, + 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */, ); path = App; sourceTree = ""; @@ -270,6 +274,7 @@ 0D6AB6C122BB05E200EEE540 /* LaunchScreen.storyboard in Resources */, 0D6AB6BE22BB05E200EEE540 /* Assets.xcassets in Resources */, 0D6AB6BC22BB05E100EEE540 /* Main.storyboard in Resources */, + 0D48E9ED2DCE7B16005474A1 /* Flutter.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -277,6 +282,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0D48E9EE2DCE7B16005474A1 /* Flutter.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart b/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart index c482f49d32c3d..bbee88f0c8cd7 100644 --- a/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart +++ b/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart @@ -61,8 +61,6 @@ class LocaleInitialization extends Scenario { scrollExtentMax: 0.0, scrollExtentMin: 0.0, transform: Matrix4.identity().storage, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -123,8 +121,6 @@ class LocaleInitialization extends Scenario { scrollExtentMax: 0.0, scrollExtentMin: 0.0, transform: Matrix4.identity().storage, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', diff --git a/engine/src/flutter/tools/fuchsia/dart.gni b/engine/src/flutter/tools/fuchsia/dart.gni index d5289a84b5cfa..d2b088e6a1e41 100644 --- a/engine/src/flutter/tools/fuchsia/dart.gni +++ b/engine/src/flutter/tools/fuchsia/dart.gni @@ -8,9 +8,3 @@ gen_snapshot = "$dart_src/runtime/bin:gen_snapshot" gen_snapshot_product = "$dart_src/runtime/bin:gen_snapshot_product" prebuilt_dart = "$dart_src/tools/sdks/dart-sdk/bin/dart" - -observatory_target = "$dart_src/runtime/observatory:observatory_archive" -observatory_archive_dir = get_label_info(observatory_target, "target_gen_dir") -observatory_archive_name = get_label_info(observatory_target, "name") -observatory_archive_file = - "${observatory_archive_dir}/${observatory_archive_name}.tar" diff --git a/engine/src/flutter/tools/gn b/engine/src/flutter/tools/gn index 81e88d7dbde4f..0edd7655f5a00 100755 --- a/engine/src/flutter/tools/gn +++ b/engine/src/flutter/tools/gn @@ -188,6 +188,8 @@ def get_target_cpu(args): return 'wasm' if args.target_os == 'win': return args.windows_cpu + if args.target_os == 'qnx': + return 'arm64' # Host build. Default to x64 unless overridden. if get_host_os() == 'mac' and args.mac_cpu: @@ -610,6 +612,10 @@ def to_gn_args(args): gn_args['skia_use_gl'] = False gn_args['shell_enable_metal'] = True gn_args['skia_use_metal'] = True + elif args.target_os == 'qnx': + gn_args['skia_enable_ganesh'] = False + gn_args['skia_enable_graphite'] = False + gn_args['arm_use_neon'] = False else: gn_args['skia_use_gl'] = args.target_os != 'fuchsia' @@ -925,7 +931,9 @@ def parse_args(args): ) parser.add_argument( - '--target-os', type=str, choices=['android', 'ios', 'mac', 'linux', 'fuchsia', 'wasm', 'win'] + '--target-os', + type=str, + choices=['android', 'ios', 'mac', 'linux', 'fuchsia', 'wasm', 'win', 'qnx'] ) parser.add_argument('--android', dest='target_os', action='store_const', const='android') parser.add_argument( diff --git a/engine/src/flutter/tools/pub_get_offline.py b/engine/src/flutter/tools/pub_get_offline.py index a01f55da93571..a5ad2804ef4e1 100644 --- a/engine/src/flutter/tools/pub_get_offline.py +++ b/engine/src/flutter/tools/pub_get_offline.py @@ -165,9 +165,9 @@ def main(): pub_count = 0 for package in ALL_PACKAGES: - if fetch_package(pubcmd, package) != 0: - return 1 if not package_uses_workspace_resolution(package): + if fetch_package(pubcmd, package) != 0: + return 1 pub_count = pub_count + check_package_config(package) if pub_count > 0: diff --git a/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml b/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml index 57c837ef67753..86291b0b96502 100644 --- a/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml +++ b/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml @@ -118,6 +118,10 @@ settings: '*.ipp': cpp csetjmp: cpp cfenv: cpp + execution: cpp + print: cpp + source_location: cpp + syncstream: cpp C_Cpp.default.includePath: - ${default} - ${workspaceFolder}/.. @@ -252,6 +256,17 @@ tasks: - build - -c - ios_debug_unopt + - <<: *et-task + label: ios_debug_sim_unopt_arm64 + args: + - build + - -c + - host_debug_unopt_arm64 + - "&&" + - *et-cmd + - build + - -c + - ios_debug_sim_unopt_arm64 - <<: *et-task label: android_debug_unopt_arm64 args: diff --git a/engine/src/flutter/txt/src/txt/platform_linux.cc b/engine/src/flutter/txt/src/txt/platform_linux.cc index e542d82e50477..667b26d6fb1d2 100644 --- a/engine/src/flutter/txt/src/txt/platform_linux.cc +++ b/engine/src/flutter/txt/src/txt/platform_linux.cc @@ -6,6 +6,7 @@ #if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE) #include "third_party/skia/include/ports/SkFontMgr_fontconfig.h" +#include "third_party/skia/include/ports/SkFontScanner_FreeType.h" #endif #if defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE) @@ -24,7 +25,8 @@ std::vector GetDefaultFontFamilies() { sk_sp GetDefaultFontManager(uint32_t font_initialization_data) { #if defined(SK_FONTMGR_FONTCONFIG_AVAILABLE) - static sk_sp mgr = SkFontMgr_New_FontConfig(nullptr); + static sk_sp mgr = + SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType()); #elif defined(SK_FONTMGR_FREETYPE_DIRECTORY_AVAILABLE) static sk_sp mgr = SkFontMgr_New_Custom_Directory("/usr/share/fonts/"); diff --git a/examples/api/lib/cupertino/radio/cupertino_radio.0.dart b/examples/api/lib/cupertino/radio/cupertino_radio.0.dart index 2ecfba0a7536e..a01b199d95d1c 100644 --- a/examples/api/lib/cupertino/radio/cupertino_radio.0.dart +++ b/examples/api/lib/cupertino/radio/cupertino_radio.0.dart @@ -37,33 +37,25 @@ class _CupertinoRadioExampleState extends State { @override Widget build(BuildContext context) { - return CupertinoListSection( - children: [ - CupertinoListTile( - title: const Text('Lafayette'), - leading: CupertinoRadio( - value: SingingCharacter.lafayette, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + return RadioGroup( + groupValue: _character, + onChanged: (SingingCharacter? value) { + setState(() { + _character = value; + }); + }, + child: CupertinoListSection( + children: const [ + CupertinoListTile( + title: Text('Lafayette'), + leading: CupertinoRadio(value: SingingCharacter.lafayette), ), - ), - CupertinoListTile( - title: const Text('Thomas Jefferson'), - leading: CupertinoRadio( - value: SingingCharacter.jefferson, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + CupertinoListTile( + title: Text('Thomas Jefferson'), + leading: CupertinoRadio(value: SingingCharacter.jefferson), ), - ), - ], + ], + ), ); } } diff --git a/examples/api/lib/cupertino/radio/cupertino_radio.toggleable.0.dart b/examples/api/lib/cupertino/radio/cupertino_radio.toggleable.0.dart index 2860b6c76da5c..3bcd3d3919962 100644 --- a/examples/api/lib/cupertino/radio/cupertino_radio.toggleable.0.dart +++ b/examples/api/lib/cupertino/radio/cupertino_radio.toggleable.0.dart @@ -36,37 +36,33 @@ class _CupertinoRadioExampleState extends State { @override Widget build(BuildContext context) { - return CupertinoListSection( - children: [ - CupertinoListTile( - title: const Text('Hercules Mulligan'), - leading: CupertinoRadio( - value: SingingCharacter.mulligan, - groupValue: _character, - // TRY THIS: Try setting the toggleable value to false and - // see how that changes the behavior of the widget. - toggleable: true, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + return RadioGroup( + groupValue: _character, + onChanged: (SingingCharacter? value) { + setState(() { + _character = value; + }); + }, + child: CupertinoListSection( + children: const [ + CupertinoListTile( + title: Text('Hercules Mulligan'), + leading: CupertinoRadio( + value: SingingCharacter.mulligan, + // TRY THIS: Try setting the toggleable value to false and + // see how that changes the behavior of the widget. + toggleable: true, + ), ), - ), - CupertinoListTile( - title: const Text('Eliza Hamilton'), - leading: CupertinoRadio( - value: SingingCharacter.hamilton, - groupValue: _character, - toggleable: true, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + CupertinoListTile( + title: Text('Eliza Hamilton'), + leading: CupertinoRadio( + value: SingingCharacter.hamilton, + toggleable: true, + ), ), - ), - ], + ], + ), ); } } diff --git a/examples/api/lib/material/radio/radio.0.dart b/examples/api/lib/material/radio/radio.0.dart index 13495c410808b..346556fa553a9 100644 --- a/examples/api/lib/material/radio/radio.0.dart +++ b/examples/api/lib/material/radio/radio.0.dart @@ -36,33 +36,25 @@ class _RadioExampleState extends State { @override Widget build(BuildContext context) { - return Column( - children: [ - ListTile( - title: const Text('Lafayette'), - leading: Radio( - value: SingingCharacter.lafayette, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + return RadioGroup( + groupValue: _character, + onChanged: (SingingCharacter? value) { + setState(() { + _character = value; + }); + }, + child: const Column( + children: [ + ListTile( + title: Text('Lafayette'), + leading: Radio(value: SingingCharacter.lafayette), ), - ), - ListTile( - title: const Text('Thomas Jefferson'), - leading: Radio( - value: SingingCharacter.jefferson, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, + ListTile( + title: Text('Thomas Jefferson'), + leading: Radio(value: SingingCharacter.jefferson), ), - ), - ], + ], + ), ); } } diff --git a/examples/api/lib/material/radio/radio.toggleable.0.dart b/examples/api/lib/material/radio/radio.toggleable.0.dart index e746b63ff6809..c672dd6078fbb 100644 --- a/examples/api/lib/material/radio/radio.toggleable.0.dart +++ b/examples/api/lib/material/radio/radio.toggleable.0.dart @@ -42,28 +42,30 @@ class _ToggleableExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: ListView.builder( - itemBuilder: (BuildContext context, int index) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Radio( - value: index, - groupValue: groupValue, - // TRY THIS: Try setting the toggleable value to false and - // see how that changes the behavior of the widget. - toggleable: true, - onChanged: (int? value) { - setState(() { - groupValue = value; - }); - }, - ), - Text(selections[index]), - ], - ); + body: RadioGroup( + groupValue: groupValue, + onChanged: (int? value) { + setState(() { + groupValue = value; + }); }, - itemCount: selections.length, + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Radio( + value: index, + // TRY THIS: Try setting the toggleable value to false and + // see how that changes the behavior of the widget. + toggleable: true, + ), + Text(selections[index]), + ], + ); + }, + itemCount: selections.length, + ), ), ); } diff --git a/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart index 8f618ef11ad05..a0645dd80d643 100644 --- a/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart +++ b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.0.dart @@ -29,16 +29,12 @@ class LinkedLabelRadio extends StatelessWidget { super.key, required this.label, required this.padding, - required this.groupValue, required this.value, - required this.onChanged, }); final String label; final EdgeInsets padding; - final bool groupValue; final bool value; - final ValueChanged onChanged; @override Widget build(BuildContext context) { @@ -46,13 +42,7 @@ class LinkedLabelRadio extends StatelessWidget { padding: padding, child: Row( children: [ - Radio( - groupValue: groupValue, - value: value, - onChanged: (bool? newValue) { - onChanged(newValue!); - }, - ), + Radio(value: value), RichText( text: TextSpan( text: label, @@ -86,32 +76,28 @@ class _LabeledRadioExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LinkedLabelRadio( - label: 'First tappable label text', - padding: const EdgeInsets.symmetric(horizontal: 5.0), - value: true, - groupValue: _isRadioSelected, - onChanged: (bool newValue) { - setState(() { - _isRadioSelected = newValue; - }); - }, - ), - LinkedLabelRadio( - label: 'Second tappable label text', - padding: const EdgeInsets.symmetric(horizontal: 5.0), - value: false, - groupValue: _isRadioSelected, - onChanged: (bool newValue) { - setState(() { - _isRadioSelected = newValue; - }); - }, - ), - ], + body: RadioGroup( + groupValue: _isRadioSelected, + onChanged: (bool? newValue) { + setState(() { + _isRadioSelected = newValue!; + }); + }, + child: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LinkedLabelRadio( + label: 'First tappable label text', + padding: EdgeInsets.symmetric(horizontal: 5.0), + value: true, + ), + LinkedLabelRadio( + label: 'Second tappable label text', + padding: EdgeInsets.symmetric(horizontal: 5.0), + value: false, + ), + ], + ), ), ); } diff --git a/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart index 215216d7ea592..5634f81d54540 100644 --- a/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart +++ b/examples/api/lib/material/radio_list_tile/custom_labeled_radio.1.dart @@ -23,43 +23,21 @@ class LabeledRadioApp extends StatelessWidget { } class LabeledRadio extends StatelessWidget { - const LabeledRadio({ - super.key, - required this.label, - required this.padding, - required this.groupValue, - required this.value, - required this.onChanged, - }); + const LabeledRadio({super.key, required this.label, required this.padding, required this.value}); final String label; final EdgeInsets padding; - final bool groupValue; final bool value; - final ValueChanged onChanged; @override Widget build(BuildContext context) { return InkWell( onTap: () { - if (value != groupValue) { - onChanged(value); - } + RadioGroup.maybeOf(context)?.onChanged(value); }, child: Padding( padding: padding, - child: Row( - children: [ - Radio( - groupValue: groupValue, - value: value, - onChanged: (bool? newValue) { - onChanged(newValue!); - }, - ), - Text(label), - ], - ), + child: Row(children: [Radio(value: value), Text(label)]), ), ); } @@ -78,32 +56,28 @@ class _LabeledRadioExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LabeledRadio( - label: 'This is the first label text', - padding: const EdgeInsets.symmetric(horizontal: 5.0), - value: true, - groupValue: _isRadioSelected, - onChanged: (bool newValue) { - setState(() { - _isRadioSelected = newValue; - }); - }, - ), - LabeledRadio( - label: 'This is the second label text', - padding: const EdgeInsets.symmetric(horizontal: 5.0), - value: false, - groupValue: _isRadioSelected, - onChanged: (bool newValue) { - setState(() { - _isRadioSelected = newValue; - }); - }, - ), - ], + body: RadioGroup( + groupValue: _isRadioSelected, + onChanged: (bool? newValue) { + setState(() { + _isRadioSelected = newValue!; + }); + }, + child: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LabeledRadio( + label: 'This is the first label text', + padding: EdgeInsets.symmetric(horizontal: 5.0), + value: true, + ), + LabeledRadio( + label: 'This is the second label text', + padding: EdgeInsets.symmetric(horizontal: 5.0), + value: false, + ), + ], + ), ), ); } diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart index f5231720d1287..520b6aeb22899 100644 --- a/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart +++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.0.dart @@ -36,29 +36,25 @@ class _RadioListTileExampleState extends State { @override Widget build(BuildContext context) { - return Column( - children: [ - RadioListTile( - title: const Text('Lafayette'), - value: SingingCharacter.lafayette, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, - ), - RadioListTile( - title: const Text('Thomas Jefferson'), - value: SingingCharacter.jefferson, - groupValue: _character, - onChanged: (SingingCharacter? value) { - setState(() { - _character = value; - }); - }, - ), - ], + return RadioGroup( + groupValue: _character, + onChanged: (SingingCharacter? value) { + setState(() { + _character = value; + }); + }, + child: const Column( + children: [ + RadioListTile( + title: Text('Lafayette'), + value: SingingCharacter.lafayette, + ), + RadioListTile( + title: Text('Thomas Jefferson'), + value: SingingCharacter.jefferson, + ), + ], + ), ); } } diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart index 18c1a47ed0b36..261163b1a5809 100644 --- a/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart +++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.1.dart @@ -33,47 +33,37 @@ class _RadioListTileExampleState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('RadioListTile Sample')), - body: Column( - children: [ - RadioListTile( - value: Groceries.pickles, - groupValue: _groceryItem, - onChanged: (Groceries? value) { - setState(() { - _groceryItem = value; - }); - }, - title: const Text('Pickles'), - subtitle: const Text('Supporting text'), - ), - RadioListTile( - value: Groceries.tomato, - groupValue: _groceryItem, - onChanged: (Groceries? value) { - setState(() { - _groceryItem = value; - }); - }, - title: const Text('Tomato'), - subtitle: const Text( - 'Longer supporting text to demonstrate how the text wraps and the radio is centered vertically with the text.', + body: RadioGroup( + groupValue: _groceryItem, + onChanged: (Groceries? value) { + setState(() { + _groceryItem = value; + }); + }, + child: const Column( + children: [ + RadioListTile( + value: Groceries.pickles, + title: Text('Pickles'), + subtitle: Text('Supporting text'), ), - ), - RadioListTile( - value: Groceries.lettuce, - groupValue: _groceryItem, - onChanged: (Groceries? value) { - setState(() { - _groceryItem = value; - }); - }, - title: const Text('Lettuce'), - subtitle: const Text( - "Longer supporting text to demonstrate how the text wraps and how setting 'RadioListTile.isThreeLine = true' aligns the radio to the top vertically with the text.", + RadioListTile( + value: Groceries.tomato, + title: Text('Tomato'), + subtitle: Text( + 'Longer supporting text to demonstrate how the text wraps and the radio is centered vertically with the text.', + ), ), - isThreeLine: true, - ), - ], + RadioListTile( + value: Groceries.lettuce, + title: Text('Lettuce'), + subtitle: Text( + "Longer supporting text to demonstrate how the text wraps and how setting 'RadioListTile.isThreeLine = true' aligns the radio to the top vertically with the text.", + ), + isThreeLine: true, + ), + ], + ), ), ); } diff --git a/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart b/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart index 75bde750d68f9..02aae148d7790 100644 --- a/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart +++ b/examples/api/lib/material/radio_list_tile/radio_list_tile.toggleable.0.dart @@ -42,21 +42,23 @@ class _RadioListTileExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: ListView.builder( - itemBuilder: (BuildContext context, int index) { - return RadioListTile( - value: index, - groupValue: groupValue, - toggleable: true, - title: Text(selections[index]), - onChanged: (int? value) { - setState(() { - groupValue = value; - }); - }, - ); + body: RadioGroup( + groupValue: groupValue, + onChanged: (int? value) { + setState(() { + groupValue = value; + }); }, - itemCount: selections.length, + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + return RadioListTile( + value: index, + toggleable: true, + title: Text(selections[index]), + ); + }, + itemCount: selections.length, + ), ), ); } diff --git a/examples/api/lib/widgets/radio_group/radio_group.0.dart b/examples/api/lib/widgets/radio_group/radio_group.0.dart new file mode 100644 index 0000000000000..f4d7556dd31a7 --- /dev/null +++ b/examples/api/lib/widgets/radio_group/radio_group.0.dart @@ -0,0 +1,108 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [Radio]. + +void main() => runApp(const RadioExampleApp()); + +class RadioExampleApp extends StatelessWidget { + const RadioExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Radio Group Sample')), + body: const Center(child: RadioExample()), + ), + ); + } +} + +enum SingingCharacter { lafayette, jefferson } + +enum Genre { metal, jazz, blues } + +class RadioExample extends StatelessWidget { + const RadioExample({super.key}); + + @override + Widget build(BuildContext context) { + return const Column(children: [SingingCharacterRadioGroup(), GenreRadioGroup()]); + } +} + +class SingingCharacterRadioGroup extends StatefulWidget { + const SingingCharacterRadioGroup({super.key}); + + @override + State createState() => SingingCharacterRadioGroupState(); +} + +class SingingCharacterRadioGroupState extends State { + SingingCharacter? _character = SingingCharacter.lafayette; + + @override + Widget build(BuildContext context) { + return RadioGroup( + groupValue: _character, + onChanged: (SingingCharacter? value) { + setState(() { + _character = value; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Selected: $_character'), + const ListTile( + title: Text('Lafayette'), + leading: Radio(value: SingingCharacter.lafayette), + ), + const ListTile( + title: Text('Thomas Jefferson'), + leading: Radio(value: SingingCharacter.jefferson), + ), + ], + ), + ); + } +} + +class GenreRadioGroup extends StatefulWidget { + const GenreRadioGroup({super.key}); + + @override + State createState() => GenreRadioGroupState(); +} + +class GenreRadioGroupState extends State { + Genre? _genre; + + @override + Widget build(BuildContext context) { + return RadioGroup( + groupValue: _genre, + onChanged: (Genre? value) { + setState(() { + _genre = value; + }); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Selected: $_genre'), + const ListTile( + title: Text('Metal'), + leading: Radio(toggleable: true, value: Genre.metal), + ), + const ListTile(title: Text('Jazz'), leading: Radio(value: Genre.jazz)), + const ListTile(title: Text('Blues'), leading: Radio(value: Genre.blues)), + ], + ), + ); + } +} diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index ff6dd993d52ea..dd42d9b4e2292 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -9,17 +9,17 @@ version: 1.0.0 environment: sdk: ^3.7.0-0 flutter: ">=2.5.0-6.0.pre.30 <3.0.0" +resolution: workspace + dependencies: - cupertino_icons: 1.0.8 flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any + vector_math: any + web: any + test: any dev_dependencies: integration_test: @@ -34,65 +34,9 @@ dev_dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - test: 1.26.1 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - intl: 0.20.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6451 +# PUBSPEC CHECKSUM: p9pqmd diff --git a/examples/api/test/cupertino/radio/cupertino_radio.0_test.dart b/examples/api/test/cupertino/radio/cupertino_radio.0_test.dart index c98998cc26bdb..c95dba6bb87a9 100644 --- a/examples/api/test/cupertino/radio/cupertino_radio.0_test.dart +++ b/examples/api/test/cupertino/radio/cupertino_radio.0_test.dart @@ -12,21 +12,15 @@ void main() { expect(find.byType(CupertinoRadio), findsNWidgets(2)); - CupertinoRadio radio = tester.widget( - find.byType(CupertinoRadio).first, + RadioGroup group = tester.widget( + find.byType(RadioGroup), ); - expect(radio.groupValue, example.SingingCharacter.lafayette); - - radio = tester.widget(find.byType(CupertinoRadio).last); - expect(radio.groupValue, example.SingingCharacter.lafayette); + expect(group.groupValue, example.SingingCharacter.lafayette); await tester.tap(find.byType(CupertinoRadio).last); await tester.pumpAndSettle(); - radio = tester.widget(find.byType(CupertinoRadio).last); - expect(radio.groupValue, example.SingingCharacter.jefferson); - - radio = tester.widget(find.byType(CupertinoRadio).first); - expect(radio.groupValue, example.SingingCharacter.jefferson); + group = tester.widget(find.byType(RadioGroup)); + expect(group.groupValue, example.SingingCharacter.jefferson); }); } diff --git a/examples/api/test/cupertino/radio/cupertino_radio.toggleable.0_test.dart b/examples/api/test/cupertino/radio/cupertino_radio.toggleable.0_test.dart index 5fcf9f80f6885..2b46237fc13fb 100644 --- a/examples/api/test/cupertino/radio/cupertino_radio.toggleable.0_test.dart +++ b/examples/api/test/cupertino/radio/cupertino_radio.toggleable.0_test.dart @@ -12,27 +12,21 @@ void main() { expect(find.byType(CupertinoRadio), findsNWidgets(2)); - CupertinoRadio radio = tester.widget( - find.byType(CupertinoRadio).first, + RadioGroup group = tester.widget( + find.byType(RadioGroup), ); - expect(radio.groupValue, example.SingingCharacter.mulligan); - - radio = tester.widget(find.byType(CupertinoRadio).last); - expect(radio.groupValue, example.SingingCharacter.mulligan); + expect(group.groupValue, example.SingingCharacter.mulligan); await tester.tap(find.byType(CupertinoRadio).last); await tester.pumpAndSettle(); - radio = tester.widget(find.byType(CupertinoRadio).last); - expect(radio.groupValue, example.SingingCharacter.hamilton); - - radio = tester.widget(find.byType(CupertinoRadio).first); - expect(radio.groupValue, example.SingingCharacter.hamilton); + group = tester.widget(find.byType(RadioGroup)); + expect(group.groupValue, example.SingingCharacter.hamilton); await tester.tap(find.byType(CupertinoRadio).last); await tester.pumpAndSettle(); - radio = tester.widget(find.byType(CupertinoRadio).last); - expect(radio.groupValue, null); + group = tester.widget(find.byType(RadioGroup)); + expect(group.groupValue, null); }); } diff --git a/examples/api/test/material/radio/radio.0_test.dart b/examples/api/test/material/radio/radio.0_test.dart index e79cb1ae093a4..33996d2780293 100644 --- a/examples/api/test/material/radio/radio.0_test.dart +++ b/examples/api/test/material/radio/radio.0_test.dart @@ -18,25 +18,26 @@ void main() { final Finder radioButton1 = find.byType(Radio).first; final Finder radioButton2 = find.byType(Radio).last; + final Finder radioGroup = find.byType(RadioGroup).last; await tester.tap(radioButton1); await tester.pumpAndSettle(); expect( - tester.widget>(radioButton1).groupValue, + tester.widget>(radioGroup).groupValue, tester.widget>(radioButton1).value, ); expect( - tester.widget>(radioButton2).groupValue, + tester.widget>(radioGroup).groupValue, isNot(tester.widget>(radioButton2).value), ); await tester.tap(radioButton2); await tester.pumpAndSettle(); expect( - tester.widget>(radioButton1).groupValue, + tester.widget>(radioGroup).groupValue, isNot(tester.widget>(radioButton1).value), ); expect( - tester.widget>(radioButton2).groupValue, + tester.widget>(radioGroup).groupValue, tester.widget>(radioButton2).value, ); }); diff --git a/examples/api/test/material/radio/radio.toggleable.0_test.dart b/examples/api/test/material/radio/radio.toggleable.0_test.dart index fa9b58fb90f7c..b010edd2826b9 100644 --- a/examples/api/test/material/radio/radio.toggleable.0_test.dart +++ b/examples/api/test/material/radio/radio.toggleable.0_test.dart @@ -21,8 +21,10 @@ void main() { await tester.tap(find.byType(Radio).at(i)); await tester.pump(); expect( - find.byWidgetPredicate((Widget widget) => widget is Radio && widget.groupValue == i), - findsExactly(5), + find.byWidgetPredicate( + (Widget widget) => widget is RadioGroup && widget.groupValue == i, + ), + findsOne, ); } }); diff --git a/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart b/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart index 8a60e6f41acf0..af5a7a47e0b8a 100644 --- a/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart +++ b/examples/api/test/material/radio_list_tile/custom_labeled_radio.0_test.dart @@ -15,28 +15,16 @@ void main() { final RichText richText = tester.widget(find.byType(RichText).first); expect(richText.text.toPlainText(), 'First tappable label text'); - // First Radio is initially unchecked. - Radio radio = tester.widget(find.byType(Radio).first); - expect(radio.value, true); - expect(radio.groupValue, false); - - // Last Radio is initially checked. - radio = tester.widget(find.byType(Radio).last); - expect(radio.value, false); - expect(radio.groupValue, false); + RadioGroup group = tester.widget>(find.byType(RadioGroup)); + // Second radio is checked. + expect(group.groupValue, isFalse); // Tap the first radio. await tester.tap(find.byType(Radio).first); await tester.pump(); // First Radio is now checked. - radio = tester.widget(find.byType(Radio).first); - expect(radio.value, true); - expect(radio.groupValue, true); - - // Last Radio is now unchecked. - radio = tester.widget(find.byType(Radio).last); - expect(radio.value, false); - expect(radio.groupValue, true); + group = tester.widget>(find.byType(RadioGroup)); + expect(group.groupValue, true); }); } diff --git a/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart b/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart index 47d31a65daa0a..a12e6bf987a2a 100644 --- a/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart +++ b/examples/api/test/material/radio_list_tile/custom_labeled_radio.1_test.dart @@ -11,28 +11,16 @@ void main() { testWidgets('Tapping LabeledRadio toggles the radio', (WidgetTester tester) async { await tester.pumpWidget(const example.LabeledRadioApp()); - // First Radio is initially unchecked. - Radio radio = tester.widget(find.byType(Radio).first); - expect(radio.value, true); - expect(radio.groupValue, false); - - // Last Radio is initially checked. - radio = tester.widget(find.byType(Radio).last); - expect(radio.value, false); - expect(radio.groupValue, false); + RadioGroup group = tester.widget>(find.byType(RadioGroup)); + // Second radio is checked. + expect(group.groupValue, isFalse); // Tap the first labeled radio to toggle the Radio widget. await tester.tap(find.byType(example.LabeledRadio).first); await tester.pumpAndSettle(); - // First Radio is now checked. - radio = tester.widget(find.byType(Radio).first); - expect(radio.value, true); - expect(radio.groupValue, true); - - // Last Radio is now unchecked. - radio = tester.widget(find.byType(Radio).last); - expect(radio.value, false); - expect(radio.groupValue, true); + group = tester.widget>(find.byType(RadioGroup)); + // Second radio is checked. + expect(group.groupValue, isTrue); }); } diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart index 765db2e9d7fe8..962797c4840ac 100644 --- a/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart +++ b/examples/api/test/material/radio_list_tile/radio_list_tile.0_test.dart @@ -13,26 +13,23 @@ void main() { // Find the number of RadioListTiles. expect(find.byType(RadioListTile), findsNWidgets(2)); - // The initial group value is lafayette for the first RadioListTile. - RadioListTile radioListTile = tester.widget( - find.byType(RadioListTile).first, - ); - expect(radioListTile.groupValue, example.SingingCharacter.lafayette); - - // The initial group value is lafayette for the last RadioListTile. - radioListTile = tester.widget(find.byType(RadioListTile).last); - expect(radioListTile.groupValue, example.SingingCharacter.lafayette); + // The initial group value is lafayette. + RadioGroup group = tester + .widget>( + find.byType(RadioGroup), + ); + // Second radio is checked. + expect(group.groupValue, example.SingingCharacter.lafayette); // Tap the last RadioListTile to change the group value to jefferson. await tester.tap(find.byType(RadioListTile).last); await tester.pump(); - // The group value is now jefferson for the first RadioListTile. - radioListTile = tester.widget(find.byType(RadioListTile).first); - expect(radioListTile.groupValue, example.SingingCharacter.jefferson); - - // The group value is now jefferson for the last RadioListTile. - radioListTile = tester.widget(find.byType(RadioListTile).last); - expect(radioListTile.groupValue, example.SingingCharacter.jefferson); + // The group value is now jefferson. + group = tester.widget>( + find.byType(RadioGroup), + ); + // Second radio is checked. + expect(group.groupValue, example.SingingCharacter.jefferson); }); } diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart index 58bf981f5359a..fb51907f5c165 100644 --- a/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart +++ b/examples/api/test/material/radio_list_tile/radio_list_tile.1_test.dart @@ -35,56 +35,31 @@ void main() { await tester.pumpWidget(const example.RadioListTileApp()); expect(find.byType(RadioListTile), findsNWidgets(3)); - final Finder radioListTile = find.byType(RadioListTile); // Initially the first radio is checked. - expect( - tester.widget>(radioListTile.at(0)).groupValue, - example.Groceries.pickles, - ); - expect( - tester.widget>(radioListTile.at(1)).groupValue, - example.Groceries.pickles, - ); - expect( - tester.widget>(radioListTile.at(2)).groupValue, - example.Groceries.pickles, + RadioGroup group = tester.widget>( + find.byType(RadioGroup), ); + expect(group.groupValue, example.Groceries.pickles); // Tap the second radio. await tester.tap(find.byType(Radio).at(1)); await tester.pumpAndSettle(); // The second radio is checked. - expect( - tester.widget>(radioListTile.at(0)).groupValue, - example.Groceries.tomato, - ); - expect( - tester.widget>(radioListTile.at(1)).groupValue, - example.Groceries.tomato, - ); - expect( - tester.widget>(radioListTile.at(2)).groupValue, - example.Groceries.tomato, + group = tester.widget>( + find.byType(RadioGroup), ); + expect(group.groupValue, example.Groceries.tomato); // Tap the third radio. await tester.tap(find.byType(Radio).at(2)); await tester.pumpAndSettle(); // The third radio is checked. - expect( - tester.widget>(radioListTile.at(0)).groupValue, - example.Groceries.lettuce, - ); - expect( - tester.widget>(radioListTile.at(1)).groupValue, - example.Groceries.lettuce, - ); - expect( - tester.widget>(radioListTile.at(2)).groupValue, - example.Groceries.lettuce, + group = tester.widget>( + find.byType(RadioGroup), ); + expect(group.groupValue, example.Groceries.lettuce); }); } diff --git a/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart b/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart index e8e897c3e8381..e375170d3fcb1 100644 --- a/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart +++ b/examples/api/test/material/radio_list_tile/radio_list_tile.toggleable.0_test.dart @@ -12,26 +12,23 @@ void main() { await tester.pumpWidget(const example.RadioListTileApp()); // Initially the third radio button is not selected. - Radio radio = tester.widget(find.byType(Radio).at(2)); - expect(radio.value, 2); - expect(radio.groupValue, null); + RadioGroup group = tester.widget>(find.byType(RadioGroup)); + expect(group.groupValue, null); // Tap the third radio button. await tester.tap(find.text('Philip Schuyler')); await tester.pumpAndSettle(); // The third radio button is now selected. - radio = tester.widget(find.byType(Radio).at(2)); - expect(radio.value, 2); - expect(radio.groupValue, 2); + group = tester.widget>(find.byType(RadioGroup)); + expect(group.groupValue, 2); // Tap the third radio button again. await tester.tap(find.text('Philip Schuyler')); await tester.pumpAndSettle(); // The third radio button is now unselected. - radio = tester.widget(find.byType(Radio).at(2)); - expect(radio.value, 2); - expect(radio.groupValue, null); + group = tester.widget>(find.byType(RadioGroup)); + expect(group.groupValue, null); }); } diff --git a/examples/api/test/widgets/radio_group/radio_group.0_test.dart b/examples/api/test/widgets/radio_group/radio_group.0_test.dart new file mode 100644 index 0000000000000..2ce9bfacef251 --- /dev/null +++ b/examples/api/test/widgets/radio_group/radio_group.0_test.dart @@ -0,0 +1,79 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/radio_group/radio_group.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Radio Smoke Test - character', (WidgetTester tester) async { + await tester.pumpWidget(const example.RadioExampleApp()); + + expect(find.widgetWithText(AppBar, 'Radio Group Sample'), findsOneWidget); + final Finder listTile1 = find.widgetWithText(ListTile, 'Lafayette'); + expect(listTile1, findsOneWidget); + final Finder listTile2 = find.widgetWithText(ListTile, 'Thomas Jefferson'); + expect(listTile2, findsOneWidget); + + final Finder radioButton1 = find.byType(Radio).first; + final Finder radioButton2 = find.byType(Radio).last; + final Finder radioGroup = find.byType(RadioGroup).last; + + await tester.tap(radioButton1); + await tester.pumpAndSettle(); + expect( + tester.widget>(radioGroup).groupValue, + tester.widget>(radioButton1).value, + ); + expect( + tester.widget>(radioGroup).groupValue, + isNot(tester.widget>(radioButton2).value), + ); + await tester.tap(radioButton2); + await tester.pumpAndSettle(); + expect( + tester.widget>(radioGroup).groupValue, + isNot(tester.widget>(radioButton1).value), + ); + expect( + tester.widget>(radioGroup).groupValue, + tester.widget>(radioButton2).value, + ); + }); + + testWidgets('Radio Smoke Test - genre', (WidgetTester tester) async { + await tester.pumpWidget(const example.RadioExampleApp()); + + expect(find.widgetWithText(AppBar, 'Radio Group Sample'), findsOneWidget); + final Finder listTile1 = find.widgetWithText(ListTile, 'Metal'); + expect(listTile1, findsOneWidget); + final Finder listTile2 = find.widgetWithText(ListTile, 'Jazz'); + expect(listTile2, findsOneWidget); + + final Finder radioButton1 = find.byType(Radio).first; + final Finder radioButton2 = find.byType(Radio).last; + final Finder radioGroup = find.byType(RadioGroup).last; + + await tester.tap(radioButton1); + await tester.pumpAndSettle(); + expect( + tester.widget>(radioGroup).groupValue, + tester.widget>(radioButton1).value, + ); + expect( + tester.widget>(radioGroup).groupValue, + isNot(tester.widget>(radioButton2).value), + ); + await tester.tap(radioButton2); + await tester.pumpAndSettle(); + expect( + tester.widget>(radioGroup).groupValue, + isNot(tester.widget>(radioButton1).value), + ); + expect( + tester.widget>(radioGroup).groupValue, + tester.widget>(radioButton2).value, + ); + }); +} diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index 087c50083931d..04828fbc965aa 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -4,19 +4,16 @@ description: A new flutter project. environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: h86dcv diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 5924bea065799..375c5e883389a 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -3,74 +3,20 @@ name: hello_world environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: sdk: flutter flutter_test: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webdriver: any -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: mut18q diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index 6cf8edea0359c..e16c927627f31 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -6,19 +6,15 @@ version: 1.0.0+1 environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.8 - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -29,22 +25,6 @@ dev_dependencies: # The following section is specific to Flutter. - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -57,4 +37,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 932d773a20204..1de0738dc50e6 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -3,40 +3,21 @@ name: flutter_examples_layers environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: assets: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/examples/platform_channel/ios/Runner/AppDelegate.m b/examples/platform_channel/ios/Runner/AppDelegate.m index 31512fc8c7847..c4f7970665166 100644 --- a/examples/platform_channel/ios/Runner/AppDelegate.m +++ b/examples/platform_channel/ios/Runner/AppDelegate.m @@ -6,19 +6,25 @@ #import #import "GeneratedPluginRegistrant.h" +@interface AppDelegate () +@end + @implementation AppDelegate { FlutterEventSink _eventSink; } - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - FlutterViewController* controller = - (FlutterViewController*)self.window.rootViewController; + self.pluginRegistrant = self; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} +- (void)registerWithRegistry:(NSObject*)registry { + [GeneratedPluginRegistrant registerWithRegistry:registry]; + NSObject* registrar = [registry registrarForPlugin:@"samples.flutter.io"]; FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/battery" - binaryMessenger:controller]; + binaryMessenger:registrar.messenger]; __weak typeof(self) weakSelf = self; [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { @@ -38,9 +44,8 @@ - (BOOL)application:(UIApplication*)application FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:@"samples.flutter.io/charging" - binaryMessenger:controller]; + binaryMessenger:registrar.messenger]; [chargingChannel setStreamHandler:self]; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (int)getBatteryLevel { diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 8f042db7dda64..fb4486a237430 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -3,77 +3,22 @@ name: platform_channel environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: f9g2jl diff --git a/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e67b2808af02f..fc5ae0316042f 100644 --- a/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -45,11 +46,13 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/examples/platform_channel_swift/ios/Runner/AppDelegate.swift b/examples/platform_channel_swift/ios/Runner/AppDelegate.swift index 83b04716f9158..a7c5865f6aaaf 100644 --- a/examples/platform_channel_swift/ios/Runner/AppDelegate.swift +++ b/examples/platform_channel_swift/ios/Runner/AppDelegate.swift @@ -20,18 +20,21 @@ enum MyFlutterErrorCode { } @main -@objc class AppDelegate: FlutterAppDelegate, FlutterStreamHandler { +@objc class AppDelegate: FlutterAppDelegate, FlutterStreamHandler, FlutterPluginRegistrant { private var eventSink: FlutterEventSink? override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - GeneratedPluginRegistrant.register(with: self) - guard let controller = window?.rootViewController as? FlutterViewController else { - fatalError("rootViewController is not type FlutterViewController") - } + pluginRegistrant = self + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func register(with registry: FlutterPluginRegistry) { + GeneratedPluginRegistrant.register(with: registry) + let registrar = registry.registrar(forPlugin: "battery") let batteryChannel = FlutterMethodChannel(name: ChannelName.battery, - binaryMessenger: controller.binaryMessenger) + binaryMessenger: registrar!.messenger()) batteryChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in guard call.method == "getBatteryLevel" else { @@ -42,9 +45,8 @@ enum MyFlutterErrorCode { }) let chargingChannel = FlutterEventChannel(name: ChannelName.charging, - binaryMessenger: controller.binaryMessenger) + binaryMessenger: registrar!.messenger()) chargingChannel.setStreamHandler(self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func receiveBatteryLevel(result: FlutterResult) { diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index a92631ecceb38..ccb4b3cf449a2 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -3,77 +3,22 @@ name: platform_channel_swift environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: f9g2jl diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index cdf6bac97332e..e175451934aee 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -3,15 +3,12 @@ name: platform_view environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -19,4 +16,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: h86dcv diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 97ac0c0a72656..2905f69709491 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -3,35 +3,16 @@ name: splash environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 6f99747685f82..4cae9526aa434 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -3,70 +3,16 @@ name: texture environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.26.1 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b623 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index d2caad7ebff7b..4c1f235dc47b9 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -550,12 +550,12 @@ class _CupertinoAppState extends State { BuildContext context, { required VoidCallback onPressed, required String semanticsLabel, - bool isLeftAligned = true, + bool usesDefaultAlignment = true, }) { return _CupertinoInspectorButton.iconOnly( onPressed: onPressed, semanticsLabel: semanticsLabel, - icon: isLeftAligned ? CupertinoIcons.arrow_right : CupertinoIcons.arrow_left, + icon: usesDefaultAlignment ? CupertinoIcons.arrow_right : CupertinoIcons.arrow_left, ); } diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index afc3874b1f263..768434a49bbe5 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -883,12 +883,19 @@ class _CupertinoNavigationBarState extends State { /// It should be placed at top of the screen and automatically accounts for /// the iOS status bar. /// +/// This navigation bar is expanded only in portrait orientation. In landscape +/// mode, the navigation bar remains permanently collapsed. The navigation bar +/// also collapses when scrolling in portrait mode. +/// /// Minimally, a [largeTitle] widget will appear in the middle of the app bar /// when the sliver is collapsed and transfer to the area below in larger font -/// when the sliver is expanded. +/// when the sliver is expanded. This expanded view will only trigger in +/// portrait orientation, while in landscape mode the bar will stay in its +/// collapsed view. /// -/// For advanced uses, an optional [middle] widget can be supplied to show a -/// different widget in the middle of the navigation bar when the sliver is collapsed. +/// For advanced uses, an optional [middle] widget +/// can be supplied to show a different widget in the middle of the navigation +/// bar when the sliver is collapsed. /// /// Like [CupertinoNavigationBar], it also supports a [leading] and [trailing] /// widget on the static section on top that remains while scrolling. @@ -1085,10 +1092,12 @@ class CupertinoSliverNavigationBar extends StatefulWidget { /// A widget to place in the middle of the static navigation bar instead of /// the [largeTitle]. /// - /// This widget is visible in both collapsed and expanded states if - /// [alwaysShowMiddle] is true, otherwise just in collapsed state. The text - /// supplied in [largeTitle] will no longer appear in collapsed state if a - /// [middle] widget is provided. + /// If [alwaysShowMiddle] is true, this widget is visible in both the + /// collapsed and expanded states of the navigation bar. Else, it is visible + /// only in the collapsed state. + /// + /// If null, [largeTitle] will be displayed in the navigation bar's collapsed + /// state. final Widget? middle; /// {@macro flutter.cupertino.CupertinoNavigationBar.trailing} @@ -1742,7 +1751,7 @@ class _RenderLargeTitle extends RenderShiftedBox { super.applyPaintTransform(child, transform); - transform.scale(_scale, _scale); + transform.scaleByDouble(_scale, _scale, _scale, 1); } @override @@ -1776,8 +1785,8 @@ class _RenderLargeTitle extends RenderShiftedBox { final Matrix4 transform = Matrix4.identity() - ..scale(1.0 / _scale, 1.0 / _scale, 1.0) - ..translate(-childOffset.dx, -childOffset.dy); + ..scaleByDouble(1.0 / _scale, 1.0 / _scale, 1.0, 1) + ..translateByDouble(-childOffset.dx, -childOffset.dy, 0, 1); return result.addWithRawTransform( transform: transform, @@ -2357,7 +2366,7 @@ class _BackChevron extends StatelessWidget { switch (textDirection) { case TextDirection.rtl: iconWidget = Transform( - transform: Matrix4.identity()..scale(-1.0, 1.0, 1.0), + transform: Matrix4.identity()..scaleByDouble(-1.0, 1.0, 1.0, 1), alignment: Alignment.center, transformHitTests: false, child: iconWidget, @@ -3060,7 +3069,6 @@ class _NavigationBarComponentsTransition { final KeyedSubtree? bottomLargeTitle = bottomComponents.largeTitleKey.currentWidget as KeyedSubtree?; final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?; - final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?; if (bottomLargeTitle == null || !bottomLargeExpanded) { return null; @@ -3093,32 +3101,28 @@ class _NavigationBarComponentsTransition { ); } - if (topLeading != null) { - // Unlike bottom middle, the bottom large title moves when it can't - // transition to the top back label position. - final RelativeRect from = positionInTransitionBox( - bottomComponents.largeTitleKey, - from: bottomNavBarBox, - ); - - final RelativeRectTween positionTween = RelativeRectTween( - begin: from, - end: from.shift(Offset(forwardDirection * bottomNavBarBox.size.width / 4.0, 0.0)), - ); + // Unlike bottom middle, the bottom large title moves when it can't + // transition to the top back label position. + final RelativeRect from = positionInTransitionBox( + bottomComponents.largeTitleKey, + from: bottomNavBarBox, + ); - // Just shift slightly towards the trailing edge instead of moving to the - // back label position. - return PositionedTransition( - rect: animation.drive(positionTween), - child: FadeTransition( - opacity: fadeOutBy(0.4), - // Keep the font when transitioning into a non-back-label leading. - child: DefaultTextStyle(style: bottomLargeTitleTextStyle!, child: bottomLargeTitle.child), - ), - ); - } + final RelativeRectTween positionTween = RelativeRectTween( + begin: from, + end: from.shift(Offset(forwardDirection * bottomNavBarBox.size.width / 4.0, 0.0)), + ); - return null; + // Just shift slightly towards the trailing edge instead of moving to the + // back label position. + return PositionedTransition( + rect: animation.drive(positionTween), + child: FadeTransition( + opacity: fadeOutBy(0.4), + // Keep the font when transitioning into a non-back-label leading. + child: DefaultTextStyle(style: bottomLargeTitleTextStyle!, child: bottomLargeTitle.child), + ), + ); } Widget? get bottomTrailing { diff --git a/packages/flutter/lib/src/cupertino/radio.dart b/packages/flutter/lib/src/cupertino/radio.dart index 9d9b1bc88fe9b..7a9ff248236f7 100644 --- a/packages/flutter/lib/src/cupertino/radio.dart +++ b/packages/flutter/lib/src/cupertino/radio.dart @@ -57,7 +57,7 @@ const double _kBorderOutlineStrokeWidth = 0.3; const List _kDarkGradientOpacities = [0.14, 0.29]; const List _kDisabledDarkGradientOpacities = [0.08, 0.14]; -/// A macOS-style radio button. +/// A widget that builds a [RawRadio] with a macOS-style UI. /// /// Used to select between a number of mutually exclusive values. When one radio /// button in a group is selected, the other radio buttons in the group are @@ -103,8 +103,16 @@ class CupertinoRadio extends StatefulWidget { const CupertinoRadio({ super.key, required this.value, - required this.groupValue, - required this.onChanged, + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.groupValue, + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.onChanged, this.mouseCursor, this.toggleable = false, this.activeColor, @@ -114,15 +122,21 @@ class CupertinoRadio extends StatefulWidget { this.focusNode, this.autofocus = false, this.useCheckmarkStyle = false, + this.enabled, + this.groupRegistry, }); /// {@macro flutter.widget.RawRadio.value} final T value; - /// {@macro flutter.widget.RawRadio.groupValue} + /// {@macro flutter.material.Radio.groupValue} + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final T? groupValue; - /// {@macro flutter.widget.RawRadio.onChanged} + /// {@macro flutter.material.Radio.onChanged} /// /// For example: /// @@ -137,6 +151,10 @@ class CupertinoRadio extends StatefulWidget { /// }, /// ) /// ``` + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final ValueChanged? onChanged; /// {@macro flutter.widget.RawRadio.mouseCursor} @@ -194,6 +212,15 @@ class CupertinoRadio extends StatefulWidget { /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; + /// {@macro flutter.widget.RawRadio.groupRegistry} + /// + /// Unless provided, the [BuildContext] will be used to look up the ancestor + /// [RadioGroupRegistry]. + final RadioGroupRegistry? groupRegistry; + + /// {@macro flutter.material.Radio.enabled} + final bool? enabled; + @override State> createState() => _CupertinoRadioState(); } @@ -202,6 +229,27 @@ class _CupertinoRadioState extends State> { FocusNode get _effectiveFocusNode => widget.focusNode ?? (_internalFocusNode ??= FocusNode()); FocusNode? _internalFocusNode; + bool get _enabled => + widget.enabled ?? + (widget.onChanged != null || + widget.groupRegistry != null || + RadioGroup.maybeOf(context) != null); + + _RadioRegistry? _internalRadioRegistry; + RadioGroupRegistry get _effectiveRegistry { + if (widget.groupRegistry != null) { + return widget.groupRegistry!; + } + + final RadioGroupRegistry? inheritedRegistry = RadioGroup.maybeOf(context); + if (inheritedRegistry != null) { + return inheritedRegistry; + } + + // Handles deprecated API. + return _internalRadioRegistry ??= _RadioRegistry(this); + } + @override void dispose() { _internalFocusNode?.dispose(); @@ -210,6 +258,14 @@ class _CupertinoRadioState extends State> { @override Widget build(BuildContext context) { + assert( + !(widget.enabled ?? false) || + widget.onChanged != null || + widget.groupRegistry != null || + RadioGroup.maybeOf(context) != null, + 'Radio is enabled but has no CupertinoRadio.onChange, ' + 'CupertinoRadio.groupRegistry, or RadioGroup above', + ); final WidgetStateProperty effectiveMouseCursor = WidgetStateProperty.resolveWith((Set states) { return WidgetStateProperty.resolveAs(widget.mouseCursor, states) ?? @@ -220,12 +276,12 @@ class _CupertinoRadioState extends State> { return RawRadio( value: widget.value, - groupValue: widget.groupValue, - onChanged: widget.onChanged, + groupRegistry: _effectiveRegistry, mouseCursor: effectiveMouseCursor, toggleable: widget.toggleable, focusNode: _effectiveFocusNode, autofocus: widget.autofocus, + enabled: _enabled, builder: (BuildContext context, ToggleableStateMixin state) { return _RadioPaint( activeColor: widget.activeColor, @@ -233,7 +289,7 @@ class _CupertinoRadioState extends State> { fillColor: widget.fillColor, focusColor: widget.focusColor, useCheckmarkStyle: widget.useCheckmarkStyle, - isActive: widget.onChanged != null, + isActive: _enabled, toggleableState: state, focused: _effectiveFocusNode.hasFocus, ); @@ -242,6 +298,24 @@ class _CupertinoRadioState extends State> { } } +/// A registry for deprecated API. +// TODO(chunhtai): Remove this once deprecated API is removed. +class _RadioRegistry extends RadioGroupRegistry { + _RadioRegistry(this.state); + final _CupertinoRadioState state; + @override + T? get groupValue => state.widget.groupValue; + + @override + ValueChanged get onChanged => state.widget.onChanged!; + + @override + void registerClient(RadioClient radio) {} + + @override + void unregisterClient(RadioClient radio) {} +} + class _RadioPaint extends StatefulWidget { const _RadioPaint({ required this.focused, diff --git a/packages/flutter/lib/src/cupertino/search_field.dart b/packages/flutter/lib/src/cupertino/search_field.dart index d13524df0d7be..473e7c4474f1e 100644 --- a/packages/flutter/lib/src/cupertino/search_field.dart +++ b/packages/flutter/lib/src/cupertino/search_field.dart @@ -483,10 +483,17 @@ class _CupertinoSearchTextFieldState extends State wit Widget build(BuildContext context) { final String placeholder = widget.placeholder ?? CupertinoLocalizations.of(context).searchTextFieldPlaceholderLabel; - + final Color defaultPlaceholderColor = CupertinoDynamicColor.resolve( + CupertinoColors.secondaryLabel, + context, + ); final TextStyle placeholderStyle = widget.placeholderStyle ?? - TextStyle(color: CupertinoColors.systemGrey.withOpacity(1.0 - _fadeExtent)); + TextStyle( + color: defaultPlaceholderColor.withAlpha( + (255 * (defaultPlaceholderColor.a * (1 - _fadeExtent))).round(), + ), + ); // The icon size will be scaled by a factor of the accessibility text scale, // to follow the behavior of `UISearchTextField`. diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 8e705a9e53512..c9209a565c21d 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -1879,6 +1879,6 @@ class _RenderBaselineAlignedStack extends RenderBox width = math.max(width, editableTextSize.width); final Size size = Size(width, height); assert(size.isFinite); - return size; + return constraints.constrain(size); } } diff --git a/packages/flutter/lib/src/cupertino/text_selection.dart b/packages/flutter/lib/src/cupertino/text_selection.dart index 2a73ed5c50f38..bec1cda2be7f8 100644 --- a/packages/flutter/lib/src/cupertino/text_selection.dart +++ b/packages/flutter/lib/src/cupertino/text_selection.dart @@ -141,9 +141,9 @@ class CupertinoTextSelectionControls extends TextSelectionControls { return Transform( transform: Matrix4.identity() - ..translate(desiredSize.width / 2, desiredSize.height / 2) + ..translateByDouble(desiredSize.width / 2, desiredSize.height / 2, 0, 1) ..rotateZ(math.pi) - ..translate(-desiredSize.width / 2, -desiredSize.height / 2), + ..translateByDouble(-desiredSize.width / 2, -desiredSize.height / 2, 0, 1), child: handle, ); // iOS should draw an invisible box so the handle can still receive gestures diff --git a/packages/flutter/lib/src/gestures/hit_test.dart b/packages/flutter/lib/src/gestures/hit_test.dart index 7c86202104552..6131b865cb3cb 100644 --- a/packages/flutter/lib/src/gestures/hit_test.dart +++ b/packages/flutter/lib/src/gestures/hit_test.dart @@ -103,7 +103,7 @@ class _OffsetTransformPart extends _TransformPart { @override Matrix4 multiply(Matrix4 rhs) { - return rhs.clone()..leftTranslate(offset.dx, offset.dy); + return rhs.clone()..leftTranslateByDouble(offset.dx, offset.dy, 0, 1); } } diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index f1852af900c7f..03d0d14646193 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -951,12 +951,12 @@ class _MaterialAppState extends State { BuildContext context, { required VoidCallback onPressed, required String semanticsLabel, - bool isLeftAligned = true, + bool usesDefaultAlignment = true, }) { return _MaterialInspectorButton.iconOnly( onPressed: onPressed, semanticsLabel: semanticsLabel, - icon: isLeftAligned ? Icons.arrow_right : Icons.arrow_left, + icon: usesDefaultAlignment ? Icons.arrow_right : Icons.arrow_left, isDarkTheme: _isDarkTheme(context), ); } diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index ea38d8bf58b97..88aae06e050f1 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -333,7 +333,8 @@ class _FlexibleSpaceBarState extends State { begin: widget.expandedTitleScale, end: 1.0, ).transform(t); - final Matrix4 scaleTransform = Matrix4.identity()..scale(scaleValue, scaleValue, 1.0); + final Matrix4 scaleTransform = + Matrix4.identity()..scaleByDouble(scaleValue, scaleValue, 1.0, 1); final Alignment titleAlignment = _getTitleAlignment(effectiveCenterTitle); children.add( Padding( diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index b65ed44d04eed..26fd7226a4b09 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -1604,8 +1604,8 @@ class _RenderDecoration extends RenderBox final double dy = lerpDouble(0.0, floatingY - labelOffset.dy, t)!; _labelTransform = Matrix4.identity() - ..translate(dx, labelOffset.dy + dy) - ..scale(scale); + ..translateByDouble(dx, labelOffset.dy + dy, 0, 1) + ..scaleByDouble(scale, scale, scale, 1); layer = context.pushTransform( needsCompositing, offset, @@ -1636,7 +1636,7 @@ class _RenderDecoration extends RenderBox final Offset labelOffset = _boxParentData(label!).offset; transform ..multiply(_labelTransform!) - ..translate(-labelOffset.dx, -labelOffset.dy); + ..translateByDouble(-labelOffset.dx, -labelOffset.dy, 0, 1); } super.applyPaintTransform(child, transform); } diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index 8746f71c0d44a..fc6b3863b3d55 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -121,6 +121,11 @@ class _MenuAnchorScope extends InheritedWidget { /// [MenuBar], used in situations where a [MenuBar] isn't appropriate, or to /// construct widgets or screen regions that have submenus. /// +/// To programmatically control a [MenuAnchor], like opening or closing it, or checking its state, +/// you can get its associated [MenuController]. Use `MenuController.maybeOf(BuildContext context)` +/// to retrieve the controller for the closest [MenuAnchor] ancestor of a given [BuildContext]. +/// More detailed usage of [MenuController] is available in its class documentation. +/// /// {@tool dartpad} /// This example shows how to use a [MenuAnchor] to wrap a button and open a /// cascading menu from the button. diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index 83217782071fd..9465e7ef96f37 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -16,7 +16,6 @@ import 'package:flutter/widgets.dart'; import 'color_scheme.dart'; import 'colors.dart'; import 'elevation_overlay.dart'; -import 'ink_decoration.dart'; import 'ink_well.dart'; import 'material.dart'; import 'material_localizations.dart'; @@ -869,7 +868,7 @@ class NavigationIndicator extends StatelessWidget { builder: (BuildContext context, Animation fadeAnimation) { return FadeTransition( opacity: fadeAnimation, - child: Ink( + child: Container( width: width, height: height, decoration: ShapeDecoration( diff --git a/packages/flutter/lib/src/material/navigation_drawer.dart b/packages/flutter/lib/src/material/navigation_drawer.dart index eb3f5ec2edd6f..99932ba48bf7d 100644 --- a/packages/flutter/lib/src/material/navigation_drawer.dart +++ b/packages/flutter/lib/src/material/navigation_drawer.dart @@ -57,6 +57,8 @@ class NavigationDrawer extends StatelessWidget { const NavigationDrawer({ super.key, required this.children, + this.header, + this.footer, this.backgroundColor, this.shadowColor, this.surfaceTintColor, @@ -120,6 +122,16 @@ class NavigationDrawer extends StatelessWidget { /// widgets like headlines and dividers. final List children; + /// A widget to display at the top of the layout. + /// + /// Typically used for titles, navigation bars, or other header content. + final Widget? header; + + /// A widget to display at the bottom of the layout. + /// + /// Typically used for actions, navigation controls, or other footer content. + final Widget? footer; + /// The index into destinations for the current selected /// [NavigationDrawerDestination] or null if no destination is selected. /// @@ -173,7 +185,16 @@ class NavigationDrawer extends StatelessWidget { shadowColor: shadowColor ?? navigationDrawerTheme.shadowColor, surfaceTintColor: surfaceTintColor ?? navigationDrawerTheme.surfaceTintColor, elevation: elevation ?? navigationDrawerTheme.elevation, - child: SafeArea(bottom: false, child: ListView(children: wrappedChildren)), + child: SafeArea( + bottom: false, + child: Column( + children: [ + if (header != null) header!, + Expanded(child: ListView(children: wrappedChildren)), + if (footer != null) footer!, + ], + ), + ), ); } } diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index c8777ffa0a7c5..1f40c46c280b5 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -1261,10 +1261,10 @@ void _updateScaledTransform(Matrix4 transform, double scale, Size size) { if (scale == 1.0) { return; } - transform.scale(scale, scale); + transform.scaleByDouble(scale, scale, scale, 1); final double dx = ((size.width * scale) - size.width) / 2; final double dy = ((size.height * scale) - size.height) / 2; - transform.translate(-dx, -dy); + transform.translateByDouble(-dx, -dy, 0, 1); } mixin _ZoomTransitionBase on State { diff --git a/packages/flutter/lib/src/material/radio.dart b/packages/flutter/lib/src/material/radio.dart index 1f3616652824f..ef1baacaf9d3e 100644 --- a/packages/flutter/lib/src/material/radio.dart +++ b/packages/flutter/lib/src/material/radio.dart @@ -34,23 +34,23 @@ const double _kInnerRadius = 4.5; /// A Material Design radio button. /// +/// This widget builds a [RawRadio] with a material UI. +/// /// Used to select between a number of mutually exclusive values. When one radio /// button in a group is selected, the other radio buttons in the group cease to /// be selected. The values are of type `T`, the type parameter of the [Radio] /// class. Enums are commonly used for this purpose. /// -/// The radio button itself does not maintain any state. Instead, selecting the -/// radio invokes the [onChanged] callback, passing [value] as a parameter. If -/// [groupValue] and [value] match, this radio will be selected. Most widgets -/// will respond to [onChanged] by calling [State.setState] to update the -/// radio button's [groupValue]. +/// This widget typically has a [RadioGroup] ancestor, which takes in a +/// [RadioGroup.groupValue], and the [Radio] under it with matching [value] +/// will be selected. /// /// {@tool dartpad} /// Here is an example of Radio widgets wrapped in ListTiles, which is similar /// to what you could get with the RadioListTile widget. /// -/// The currently selected character is passed into `groupValue`, which is -/// maintained by the example's `State`. In this case, the first [Radio] +/// The currently selected character is passed into `RadioGroup.groupValue`, +/// which is maintained by the example's `State`. In this case, the first [Radio] /// will start off selected because `_character` is initialized to /// `SingingCharacter.lafayette`. /// @@ -71,25 +71,27 @@ const double _kInnerRadius = 4.5; /// * [Slider], for selecting a value in a range. /// * [Checkbox] and [Switch], for toggling a particular value on or off. /// * -class Radio extends StatelessWidget { +class Radio extends StatefulWidget { /// Creates a Material Design radio button. /// - /// The radio button itself does not maintain any state. Instead, when the - /// radio button is selected, the widget calls the [onChanged] callback. Most - /// widgets that use a radio button will listen for the [onChanged] callback - /// and rebuild the radio button with a new [groupValue] to update the visual - /// appearance of the radio button. - /// - /// The following arguments are required: + /// This widget typically has a [RadioGroup] ancestor, which takes in a + /// [RadioGroup.groupValue], and the [Radio] under it with matching [value] + /// will be selected. /// - /// * [value] and [groupValue] together determine whether the radio button is - /// selected. - /// * [onChanged] is called when the user selects this radio button. + /// The [value] is required. const Radio({ super.key, required this.value, - required this.groupValue, - required this.onChanged, + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.groupValue, + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.onChanged, this.mouseCursor, this.toggleable = false, this.activeColor, @@ -102,6 +104,8 @@ class Radio extends StatelessWidget { this.visualDensity, this.focusNode, this.autofocus = false, + this.enabled, + this.groupRegistry, }) : _radioType = _RadioType.material, useCupertinoCheckmarkStyle = false; @@ -124,8 +128,16 @@ class Radio extends StatelessWidget { const Radio.adaptive({ super.key, required this.value, - required this.groupValue, - required this.onChanged, + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.groupValue, + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.onChanged, this.mouseCursor, this.toggleable = false, this.activeColor, @@ -139,15 +151,46 @@ class Radio extends StatelessWidget { this.focusNode, this.autofocus = false, this.useCupertinoCheckmarkStyle = false, + this.enabled, + this.groupRegistry, }) : _radioType = _RadioType.adaptive; /// {@macro flutter.widget.RawRadio.value} final T value; - /// {@macro flutter.widget.RawRadio.groupValue} + /// {@template flutter.material.Radio.groupValue} + /// The currently selected value for a group of radio buttons. + /// + /// This radio button is considered selected if its [value] matches the + /// [groupValue]. + /// + /// This is deprecated, use [RadioGroup] to manage group value instead. + /// {@endtemplate} + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final T? groupValue; - /// {@macro flutter.widget.RawRadio.onChanged} + /// {@template flutter.material.Radio.onChanged} + /// Called when the user selects this radio button. + /// + /// The radio button passes [value] as a parameter to this callback. The radio + /// button does not actually change state until the parent widget rebuilds the + /// radio button with the new [groupValue]. + /// + /// If null, the radio button will be displayed as disabled. + /// + /// The provided callback will not be invoked if this radio button is already + /// selected and [toggleable] is not set to true. + /// + /// If the [toggleable] is set to true, tapping a already selected radio will + /// invoke this callback with `null` as value. + /// + /// The callback provided to [onChanged] should update the state of the parent + /// [StatefulWidget] using the [State.setState] method, so that the parent + /// gets rebuilt. + /// {@endtemplate} /// /// For example: /// @@ -162,6 +205,12 @@ class Radio extends StatelessWidget { /// }, /// ) /// ``` + /// + /// This is deprecated, use [RadioGroup] to handle value change instead. + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final ValueChanged? onChanged; /// {@macro flutter.widget.RawRadio.mouseCursor} @@ -205,8 +254,6 @@ class Radio extends StatelessWidget { /// ```dart /// Radio( /// value: 1, - /// groupValue: 1, - /// onChanged: (_){}, /// fillColor: WidgetStateProperty.resolveWith((Set states) { /// if (states.contains(WidgetState.disabled)) { /// return Colors.orange.withOpacity(.32); @@ -328,12 +375,75 @@ class Radio extends StatelessWidget { /// Defaults to false. final bool useCupertinoCheckmarkStyle; + /// {@macro flutter.widget.RawRadio.groupRegistry} + /// + /// Unless provided, the [BuildContext] will be used to look up the ancestor + /// [RadioGroupRegistry]. + final RadioGroupRegistry? groupRegistry; + final _RadioType _radioType; + /// {@template flutter.material.Radio.enabled} + /// Whether this widget is interactive. + /// + /// If not provided, this widget will be interactable if one of the following + /// is true: + /// + /// * A [onChanged] is provided. + /// * Having a [RadioGroup] with the same type T above this widget. + /// * A [groupRegistry] is provided. + /// + /// If this is set to true, one of the above condition must also be true. + /// Otherwise, an assertion error is thrown. + /// {@endtemplate} + final bool? enabled; + + @override + State> createState() => _RadioState(); +} + +class _RadioState extends State> { + FocusNode? _internalFocusNode; + FocusNode get _focusNode => widget.focusNode ?? (_internalFocusNode ??= FocusNode()); + + bool get _enabled => + widget.enabled ?? + (widget.onChanged != null || + widget.groupRegistry != null || + RadioGroup.maybeOf(context) != null); + + _RadioRegistry? _internalRadioRegistry; + RadioGroupRegistry get _effectiveRegistry { + if (widget.groupRegistry != null) { + return widget.groupRegistry!; + } + + final RadioGroupRegistry? inheritedRegistry = RadioGroup.maybeOf(context); + if (inheritedRegistry != null) { + return inheritedRegistry; + } + + // Handles deprecated API. + return _internalRadioRegistry ??= _RadioRegistry(this); + } + + @override + void dispose() { + _internalFocusNode?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { + assert( + !(widget.enabled ?? false) || + widget.onChanged != null || + widget.groupRegistry != null || + RadioGroup.maybeOf(context) != null, + 'Radio is enabled but has no Radio.onChange or registry above', + ); assert(debugCheckHasMaterial(context)); - switch (_radioType) { + switch (widget._radioType) { case _RadioType.material: break; @@ -348,16 +458,18 @@ class Radio extends StatelessWidget { case TargetPlatform.iOS: case TargetPlatform.macOS: return CupertinoRadio( - value: value, - groupValue: groupValue, - onChanged: onChanged, - mouseCursor: mouseCursor, - toggleable: toggleable, - activeColor: activeColor, - focusColor: focusColor, - focusNode: focusNode, - autofocus: autofocus, - useCheckmarkStyle: useCupertinoCheckmarkStyle, + value: widget.value, + groupValue: widget.groupValue, + onChanged: widget.onChanged, + mouseCursor: widget.mouseCursor, + toggleable: widget.toggleable, + activeColor: widget.activeColor, + focusColor: widget.focusColor, + focusNode: _focusNode, + autofocus: widget.autofocus, + useCheckmarkStyle: widget.useCupertinoCheckmarkStyle, + groupRegistry: _effectiveRegistry, + enabled: _enabled, ); } } @@ -365,39 +477,56 @@ class Radio extends StatelessWidget { final RadioThemeData radioTheme = RadioTheme.of(context); final MaterialStateProperty effectiveMouseCursor = MaterialStateProperty.resolveWith((Set states) { - return MaterialStateProperty.resolveAs(mouseCursor, states) ?? + return MaterialStateProperty.resolveAs(widget.mouseCursor, states) ?? radioTheme.mouseCursor?.resolve(states) ?? MaterialStateProperty.resolveAs( MaterialStateMouseCursor.clickable, states, ); }); - return RawRadio( - value: value, - groupValue: groupValue, - onChanged: onChanged, + value: widget.value, mouseCursor: effectiveMouseCursor, - toggleable: toggleable, - focusNode: focusNode, - autofocus: autofocus, + toggleable: widget.toggleable, + focusNode: _focusNode, + autofocus: widget.autofocus, + groupRegistry: _effectiveRegistry, + enabled: _enabled, builder: (BuildContext context, ToggleableStateMixin state) { return _RadioPaint( toggleableState: state, - activeColor: activeColor, - fillColor: fillColor, - hoverColor: hoverColor, - focusColor: focusColor, - overlayColor: overlayColor, - splashRadius: splashRadius, - visualDensity: visualDensity, - materialTapTargetSize: materialTapTargetSize, + activeColor: widget.activeColor, + fillColor: widget.fillColor, + hoverColor: widget.hoverColor, + focusColor: widget.focusColor, + overlayColor: widget.overlayColor, + splashRadius: widget.splashRadius, + visualDensity: widget.visualDensity, + materialTapTargetSize: widget.materialTapTargetSize, ); }, ); } } +/// A registry for deprecated API. +// TODO(chunhtai): Remove this once deprecated API is removed. +class _RadioRegistry extends RadioGroupRegistry { + _RadioRegistry(this.state); + final _RadioState state; + @override + T? get groupValue => state.widget.groupValue; + + @override + ValueChanged get onChanged => state.widget.onChanged!; + + @override + void registerClient(RadioClient radio) {} + + @override + void unregisterClient(RadioClient radio) {} +} + class _RadioPaint extends StatefulWidget { const _RadioPaint({ required this.toggleableState, diff --git a/packages/flutter/lib/src/material/radio_list_tile.dart b/packages/flutter/lib/src/material/radio_list_tile.dart index 7da8f90fe9816..8bad89ed56465 100644 --- a/packages/flutter/lib/src/material/radio_list_tile.dart +++ b/packages/flutter/lib/src/material/radio_list_tile.dart @@ -37,10 +37,9 @@ enum _RadioType { material, adaptive } /// The entire list tile is interactive: tapping anywhere in the tile selects /// the radio button. /// -/// The [value], [groupValue], [onChanged], and [activeColor] properties of this -/// widget are identical to the similarly-named properties on the [Radio] -/// widget. The type parameter `T` serves the same purpose as that of the -/// [Radio] class' type parameter. +/// This widget typically has a [RadioGroup] ancestor, which takes in a +/// [RadioGroup.groupValue], and the [RadioListTile] under it with matching +/// [value] will be selected. /// /// The [title], [subtitle], [isThreeLine], and [dense] properties are like /// those of the same name on [ListTile]. @@ -67,15 +66,13 @@ enum _RadioType { material, adaptive } /// /// {@tool snippet} /// ```dart -/// ColoredBox( +/// const ColoredBox( /// color: Colors.green, /// child: Material( /// child: RadioListTile( /// tileColor: Colors.red, -/// title: const Text('AM'), -/// groupValue: Meridiem.am, +/// title: Text('AM'), /// value: Meridiem.am, -/// onChanged:(Meridiem? value) { }, /// ), /// ), /// ) @@ -88,9 +85,6 @@ enum _RadioType { material, adaptive } /// is expensive. Consider only wrapping the [RadioListTile]s that require it /// or include a common [Material] ancestor where possible. /// -/// To show the [RadioListTile] as disabled, pass null as the [onChanged] -/// callback. -/// /// {@tool dartpad} /// ![RadioListTile sample](https://flutter.github.io/assets-for-api-docs/assets/material/radio_list_tile.png) /// @@ -157,25 +151,27 @@ enum _RadioType { material, adaptive } /// * [CheckboxListTile], a similar widget for checkboxes. /// * [SwitchListTile], a similar widget for switches. /// * [ListTile] and [Radio], the widgets from which this widget is made. -class RadioListTile extends StatelessWidget { +class RadioListTile extends StatefulWidget { /// Creates a combination of a list tile and a radio button. /// - /// The radio tile itself does not maintain any state. Instead, when the radio - /// button is selected, the widget calls the [onChanged] callback. Most - /// widgets that use a radio button will listen for the [onChanged] callback - /// and rebuild the radio tile with a new [groupValue] to update the visual - /// appearance of the radio button. - /// - /// The following arguments are required: + /// This widget typically has a [RadioGroup] ancestor, which takes in a + /// [RadioGroup.groupValue], and the [RadioListTile] under it with matching + /// [value] will be selected. /// - /// * [value] and [groupValue] together determine whether the radio button is - /// selected. - /// * [onChanged] is called when the user selects this radio button. + /// [value] must be provided const RadioListTile({ super.key, required this.value, - required this.groupValue, - required this.onChanged, + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.groupValue, + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.onChanged, this.mouseCursor, this.toggleable = false, this.activeColor, @@ -202,6 +198,7 @@ class RadioListTile extends StatelessWidget { this.enableFeedback, this.radioScaleFactor = 1.0, this.titleAlignment, + this.enabled, this.internalAddSemanticForOnTap = false, }) : _radioType = _RadioType.material, useCupertinoCheckmarkStyle = false, @@ -216,8 +213,16 @@ class RadioListTile extends StatelessWidget { const RadioListTile.adaptive({ super.key, required this.value, - required this.groupValue, - required this.onChanged, + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.groupValue, + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + this.onChanged, this.mouseCursor, this.toggleable = false, this.activeColor, @@ -243,6 +248,7 @@ class RadioListTile extends StatelessWidget { this.onFocusChange, this.enableFeedback, this.radioScaleFactor = 1.0, + this.enabled, this.useCupertinoCheckmarkStyle = false, this.titleAlignment, this.internalAddSemanticForOnTap = false, @@ -256,6 +262,12 @@ class RadioListTile extends StatelessWidget { /// /// This radio button is considered selected if its [value] matches the /// [groupValue]. + /// + /// leave this unassigned or null if building this widget under [RadioGroup]. + @Deprecated( + 'Use a RadioGroup ancestor to manage group value instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final T? groupValue; /// Called when the user selects this radio button. @@ -285,6 +297,10 @@ class RadioListTile extends StatelessWidget { /// }, /// ) /// ``` + @Deprecated( + 'Use RadioGroup to handle value change instead. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) final ValueChanged? onChanged; /// The cursor for a mouse pointer when it enters or is hovering over the @@ -307,14 +323,14 @@ class RadioListTile extends StatelessWidget { /// To indicate returning to an indeterminate state, [onChanged] will be /// called with null. /// - /// If true, [onChanged] is called with [value] when selected while - /// [groupValue] != [value], and with null when selected again while - /// [groupValue] == [value]. + /// If true, [RadioGroup.onChanged] is called with [value] when selected while + /// [RadioGroup.groupValue] != [value], and with null when selected again while + /// [RadioGroup.groupValue] == [value]. /// - /// If false, [onChanged] will be called with [value] when it is selected - /// while [groupValue] != [value], and only by selecting another radio button - /// in the group (i.e. changing the value of [groupValue]) can this radio - /// list tile be unselected. + /// If false, [RadioGroup.onChanged] will be called with [value] when it is + /// selected while [groupValue] != [value], and only by selecting another + /// radio button in the group (i.e. changing the value of + /// [RadioGroup.groupValue]) can this radio list tile be unselected. /// /// The default is false. /// @@ -402,7 +418,7 @@ class RadioListTile extends StatelessWidget { /// No effort is made to automatically coordinate the [selected] state and the /// [checked] state. To have the list tile appear selected when the radio /// button is the selected radio button, set [selected] to true when [value] - /// matches [groupValue]. + /// matches [RadioGroup.groupValue]. /// /// Normally, this property is left to its default value, false. final bool selected; @@ -421,11 +437,6 @@ class RadioListTile extends StatelessWidget { /// When null, `EdgeInsets.symmetric(horizontal: 16.0)` is used. final EdgeInsetsGeometry? contentPadding; - /// Whether this radio button is checked. - /// - /// To control this value, set [value] and [groupValue] appropriately. - bool get checked => value == groupValue; - /// If specified, [shape] defines the shape of the [RadioListTile]'s [InkWell] border. final ShapeBorder? shape; @@ -492,100 +503,203 @@ class RadioListTile extends StatelessWidget { /// Defaults to 1.0. final double radioScaleFactor; + /// Whether this widget is interactable. + /// + /// If not provided, this widget will be interactable if one of the following + /// is true: + /// + /// * A [onChanged] is provided. + /// * Having a [RadioGroup] with the same type T above this widget. + /// + /// If this is set to true, one of the above condition must also be true. + /// Otherwise, an assertion error is thrown. + final bool? enabled; + + /// Whether this radio button is checked. + /// + /// To control this value, set [value] and [groupValue] appropriately. + @Deprecated( + 'Use RadioGroup.groupValue to find which radio is checked. ' + 'This feature was deprecated after v3.32.0-0.0.pre.', + ) + bool get checked => value == groupValue; + + @override + State> createState() => _RadioListTileState(); +} + +class _RadioListTileState extends State> with RadioClient { + FocusNode? _internalFocusNode; + @override + FocusNode get focusNode => widget.focusNode ?? (_internalFocusNode ??= FocusNode()); + + @override + T get radioValue => widget.value; + + @override + bool get tristate => widget.toggleable; + + bool get checked => radioValue == effectiveGroupValue; + + late final _RadioRegistry _radioRegistry = _RadioRegistry(this); + + T? get effectiveGroupValue => registry?.groupValue ?? widget.groupValue; + + bool get _enabled => widget.enabled ?? (widget.onChanged != null || registry != null); + + void _handleListTileTap() { + if (!widget.toggleable && checked) { + return; + } + T? newValue; + if (checked) { + newValue = null; + } else { + newValue = radioValue; + } + handleChange(newValue); + } + + void handleChange(T? value) { + if (registry != null) { + registry!.onChanged(value); + } + + if (widget.onChanged != null) { + widget.onChanged!(value); + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + registry = RadioGroup.maybeOf(context); + } + + @override + void dispose() { + registry = null; + _internalFocusNode?.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { + assert( + !(widget.enabled ?? false) || + widget.onChanged != null || + RadioGroup.maybeOf(context) != null, + 'Radio is enabled but has no RadioListTile.onChange or registry above', + ); Widget control; - switch (_radioType) { + switch (widget._radioType) { case _RadioType.material: control = ExcludeFocus( child: Radio( - value: value, - groupValue: groupValue, - onChanged: onChanged, - toggleable: toggleable, - activeColor: activeColor, - materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap, - autofocus: autofocus, - fillColor: fillColor, - mouseCursor: mouseCursor, - hoverColor: hoverColor, - overlayColor: overlayColor, - splashRadius: splashRadius, + value: radioValue, + groupValue: _radioRegistry.groupValue, + toggleable: widget.toggleable, + activeColor: widget.activeColor, + materialTapTargetSize: widget.materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap, + autofocus: widget.autofocus, + fillColor: widget.fillColor, + mouseCursor: widget.mouseCursor, + hoverColor: widget.hoverColor, + overlayColor: widget.overlayColor, + splashRadius: widget.splashRadius, + enabled: _enabled, + groupRegistry: _radioRegistry, ), ); case _RadioType.adaptive: control = ExcludeFocus( child: Radio.adaptive( - value: value, - groupValue: groupValue, - onChanged: onChanged, - toggleable: toggleable, - activeColor: activeColor, - materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap, - autofocus: autofocus, - fillColor: fillColor, - mouseCursor: mouseCursor, - hoverColor: hoverColor, - overlayColor: overlayColor, - splashRadius: splashRadius, - useCupertinoCheckmarkStyle: useCupertinoCheckmarkStyle, + value: radioValue, + groupValue: _radioRegistry.groupValue, + toggleable: widget.toggleable, + activeColor: widget.activeColor, + materialTapTargetSize: widget.materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap, + autofocus: widget.autofocus, + fillColor: widget.fillColor, + mouseCursor: widget.mouseCursor, + hoverColor: widget.hoverColor, + overlayColor: widget.overlayColor, + splashRadius: widget.splashRadius, + useCupertinoCheckmarkStyle: widget.useCupertinoCheckmarkStyle, + enabled: _enabled, + groupRegistry: _radioRegistry, ), ); } - if (radioScaleFactor != 1.0) { - control = Transform.scale(scale: radioScaleFactor, child: control); + if (widget.radioScaleFactor != 1.0) { + control = Transform.scale(scale: widget.radioScaleFactor, child: control); } final ListTileThemeData listTileTheme = ListTileTheme.of(context); final ListTileControlAffinity effectiveControlAffinity = - controlAffinity ?? listTileTheme.controlAffinity ?? ListTileControlAffinity.platform; + widget.controlAffinity ?? listTileTheme.controlAffinity ?? ListTileControlAffinity.platform; Widget? leading, trailing; (leading, trailing) = switch (effectiveControlAffinity) { - ListTileControlAffinity.leading || ListTileControlAffinity.platform => (control, secondary), - ListTileControlAffinity.trailing => (secondary, control), + ListTileControlAffinity.leading || + ListTileControlAffinity.platform => (control, widget.secondary), + ListTileControlAffinity.trailing => (widget.secondary, control), }; - final ThemeData theme = Theme.of(context); final RadioThemeData radioThemeData = RadioTheme.of(context); - final Set states = {if (selected) MaterialState.selected}; + final Set states = {if (widget.selected) MaterialState.selected}; final Color effectiveActiveColor = - activeColor ?? radioThemeData.fillColor?.resolve(states) ?? theme.colorScheme.secondary; + widget.activeColor ?? + radioThemeData.fillColor?.resolve(states) ?? + theme.colorScheme.secondary; return MergeSemantics( child: ListTile( selectedColor: effectiveActiveColor, leading: leading, - title: title, - subtitle: subtitle, + title: widget.title, + subtitle: widget.subtitle, trailing: trailing, - isThreeLine: isThreeLine, - dense: dense, - enabled: onChanged != null, - shape: shape, - tileColor: tileColor, - selectedTileColor: selectedTileColor, - onTap: - onChanged != null - ? () { - if (toggleable && checked) { - onChanged!(null); - return; - } - if (!checked) { - onChanged!(value); - } - } - : null, - selected: selected, - autofocus: autofocus, - contentPadding: contentPadding, - visualDensity: visualDensity, + isThreeLine: widget.isThreeLine, + dense: widget.dense, + enabled: _enabled, + shape: widget.shape, + tileColor: widget.tileColor, + selectedTileColor: widget.selectedTileColor, + onTap: _enabled ? _handleListTileTap : null, + selected: widget.selected, + autofocus: widget.autofocus, + contentPadding: widget.contentPadding, + visualDensity: widget.visualDensity, focusNode: focusNode, - onFocusChange: onFocusChange, - enableFeedback: enableFeedback, - titleAlignment: titleAlignment, - internalAddSemanticForOnTap: internalAddSemanticForOnTap, + onFocusChange: widget.onFocusChange, + enableFeedback: widget.enableFeedback, + titleAlignment: widget.titleAlignment, + internalAddSemanticForOnTap: widget.internalAddSemanticForOnTap, ), ); } } + +/// A registry to controls internal [Radio] and hides it from [RadioGroup] +/// ancestor. +/// +/// [RadioListTile] implements the [RadioClient] directly to register to +/// [RadioGroup] ancestor. Therefore, it has to hide the internal [Radio] from +/// participate in the [RadioGroup] ancestor. +class _RadioRegistry extends RadioGroupRegistry { + _RadioRegistry(this.state); + + final _RadioListTileState state; + + @override + T? get groupValue => state.effectiveGroupValue; + + @override + ValueChanged get onChanged => state.handleChange; + + @override + void registerClient(RadioClient radio) {} + + @override + void unregisterClient(RadioClient radio) {} +} diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 00f5cdab52831..77d5cd8895d81 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -447,9 +447,6 @@ class SelectableText extends StatefulWidget { BuildContext context, EditableTextState editableTextState, ) { - if (defaultTargetPlatform == TargetPlatform.iOS && SystemContextMenu.isSupported(context)) { - return SystemContextMenu.editableText(editableTextState: editableTextState); - } return AdaptiveTextSelectionToolbar.editableText(editableTextState: editableTextState); } diff --git a/packages/flutter/lib/src/material/text_selection_toolbar.dart b/packages/flutter/lib/src/material/text_selection_toolbar.dart index 2c0562e75f491..f90c8c1736f9e 100644 --- a/packages/flutter/lib/src/material/text_selection_toolbar.dart +++ b/packages/flutter/lib/src/material/text_selection_toolbar.dart @@ -370,7 +370,7 @@ class _TextSelectionToolbarTrailingEdgeAlignRenderBox extends RenderProxyBox { @override void applyPaintTransform(RenderObject child, Matrix4 transform) { final ToolbarItemsParentData childParentData = child.parentData! as ToolbarItemsParentData; - transform.translate(childParentData.offset.dx, childParentData.offset.dy); + transform.translateByDouble(childParentData.offset.dx, childParentData.offset.dy, 0, 1); super.applyPaintTransform(child, transform); } } diff --git a/packages/flutter/lib/src/painting/alignment.dart b/packages/flutter/lib/src/painting/alignment.dart index 6d77171bcb00b..6f3903406e62d 100644 --- a/packages/flutter/lib/src/painting/alignment.dart +++ b/packages/flutter/lib/src/painting/alignment.dart @@ -15,8 +15,8 @@ import 'basic_types.dart'; /// Base class for [Alignment] that allows for text-direction aware /// resolution. /// -/// A property or argument of this type accepts classes created either with [ -/// Alignment] and its variants, or [AlignmentDirectional.new]. +/// A property or argument of this type accepts classes created either with +/// [Alignment] and its variants, or [AlignmentDirectional.new]. /// /// To convert an [AlignmentGeometry] object of indeterminate type into an /// [Alignment] object, call the [resolve] method. @@ -32,6 +32,69 @@ abstract class AlignmentGeometry { /// Creates a directional alignment, or [AlignmentDirectional]. const factory AlignmentGeometry.directional(double start, double y) = AlignmentDirectional; + /// The top left corner. + /// + /// See also: + /// + /// * [Alignment.topLeft], which is the same thing. + static const AlignmentGeometry topLeft = Alignment.topLeft; + + /// The center point along the top edge. + /// + /// See also: + /// + /// * [Alignment.topCenter], which is the same thing. + static const AlignmentGeometry topCenter = Alignment.topCenter; + + /// The top right corner. + /// + /// See also: + /// + /// * [Alignment.topRight], which is the same thing. + static const AlignmentGeometry topRight = Alignment.topRight; + + /// The center point along the left edge. + /// + /// See also: + /// + /// * [Alignment.centerLeft], which is the same thing. + static const AlignmentGeometry centerLeft = Alignment.centerLeft; + + /// The center point, both horizontally and vertically. + /// + /// See also: + /// + /// * [Alignment.center], which is the same thing. + static const AlignmentGeometry center = Alignment.center; + + /// The center point along the right edge. + /// + /// See also: + /// + /// * [Alignment.centerRight], which is the same thing. + static const AlignmentGeometry centerRight = Alignment.centerRight; + + /// The bottom left corner. + /// + /// See also: + /// + /// * [Alignment.bottomLeft], which is the same thing. + static const AlignmentGeometry bottomLeft = Alignment.bottomLeft; + + /// The center point along the bottom edge. + /// + /// See also: + /// + /// * [Alignment.bottomCenter], which is the same thing. + static const AlignmentGeometry bottomCenter = Alignment.bottomCenter; + + /// The bottom right corner. + /// + /// See also: + /// + /// * [Alignment.bottomRight], which is the same thing. + static const AlignmentGeometry bottomRight = Alignment.bottomRight; + double get _x; double get _start; diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart index 52a3aa7606640..f848fd689ea8b 100644 --- a/packages/flutter/lib/src/painting/gradient.dart +++ b/packages/flutter/lib/src/painting/gradient.dart @@ -121,7 +121,7 @@ class GradientRotation extends GradientTransform { final double originY = -sinRadians * center.dx + oneMinusCosRadians * center.dy; return Matrix4.identity() - ..translate(originX, originY) + ..translateByDouble(originX, originY, 0, 1) ..rotateZ(radians); } diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index aad25e1064125..04cfe5e34cced 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -17,8 +17,7 @@ import 'dart:ui' as ui show ViewConstraints, lerpDouble; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; - -import 'package:vector_math/vector_math_64.dart'; +import 'package:vector_math/vector_math_64.dart' show Matrix4, Vector3; import 'debug.dart'; import 'object.dart'; @@ -3037,7 +3036,7 @@ abstract class RenderBox extends RenderObject { }()); final BoxParentData childParentData = child.parentData! as BoxParentData; final Offset offset = childParentData.offset; - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } /// Convert the given point from the global coordinate system in logical pixels diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index 940de4277a9e8..13aa2a07b3c79 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -18,7 +18,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/painting.dart'; import 'package:flutter/scheduler.dart'; -import 'package:vector_math/vector_math_64.dart'; +import 'package:vector_math/vector_math_64.dart' show Vector4; import 'debug.dart'; @@ -1491,7 +1491,7 @@ class OffsetLayer extends ContainerLayer { @override void applyTransform(Layer? child, Matrix4 transform) { assert(child != null); - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } @override @@ -1519,7 +1519,7 @@ class OffsetLayer extends ContainerLayer { ui.Scene _createSceneForImage(Rect bounds, {double pixelRatio = 1.0}) { final ui.SceneBuilder builder = ui.SceneBuilder(); final Matrix4 transform = Matrix4.diagonal3Values(pixelRatio, pixelRatio, 1); - transform.translate(-(bounds.left + offset.dx), -(bounds.top + offset.dy)); + transform.translateByDouble(-(bounds.left + offset.dx), -(bounds.top + offset.dy), 0, 1); builder.pushTransform(transform.storage); return buildScene(builder); } @@ -2578,7 +2578,7 @@ class LeaderLayer extends ContainerLayer { @override void applyTransform(Layer? child, Matrix4 transform) { if (offset != Offset.zero) { - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } } @@ -2826,7 +2826,7 @@ class FollowerLayer extends ContainerLayer { // of the leader layer, to account for the leader's additional paint offset // and layer offset (LeaderLayer.offset). leader.applyTransform(null, forwardTransform); - forwardTransform.translate(linkedOffset!.dx, linkedOffset!.dy); + forwardTransform.translateByDouble(linkedOffset!.dx, linkedOffset!.dy, 0, 1); final Matrix4 inverseTransform = _collectTransformForLayerChain(inverseLayers); diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index 2ada75f0e8866..2027505ba48ca 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -1020,18 +1020,17 @@ class RenderListWheelViewport extends RenderBox final ListWheelParentData childParentData = child.parentData! as ListWheelParentData; // Save the final transform that accounts both for the offset and cylindrical transform. final Matrix4 transform = _centerOriginTransform(cylindricalTransform) - ..translate(paintOriginOffset.dx, paintOriginOffset.dy); + ..translateByDouble(paintOriginOffset.dx, paintOriginOffset.dy, 0, 1); childParentData.transform = transform; } /// Return the Matrix4 transformation that would zoom in content in the /// magnified area. Matrix4 _magnifyTransform() { - final Matrix4 magnify = Matrix4.identity(); - magnify.translate(size.width * (-_offAxisFraction + 0.5), size.height / 2); - magnify.scale(_magnification, _magnification, _magnification); - magnify.translate(-size.width * (-_offAxisFraction + 0.5), -size.height / 2); - return magnify; + return Matrix4.identity() + ..translateByDouble(size.width * (-_offAxisFraction + 0.5), size.height / 2, 0, 1) + ..scaleByDouble(_magnification, _magnification, _magnification, 1.0) + ..translateByDouble(-size.width * (-_offAxisFraction + 0.5), -size.height / 2, 0, 1); } /// Apply incoming transformation with the transformation's origin at the @@ -1039,14 +1038,18 @@ class RenderListWheelViewport extends RenderBox Matrix4 _centerOriginTransform(Matrix4 originalMatrix) { final Matrix4 result = Matrix4.identity(); final Offset centerOriginTranslation = Alignment.center.alongSize(size); - result.translate( + result.translateByDouble( centerOriginTranslation.dx * (-_offAxisFraction * 2 + 1), centerOriginTranslation.dy, + 0, + 1, ); result.multiply(originalMatrix); - result.translate( + result.translateByDouble( -centerOriginTranslation.dx * (-_offAxisFraction * 2 + 1), -centerOriginTranslation.dy, + 0, + 1, ); return result; } diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 9e560d4532ff8..0e533d6802206 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -780,7 +780,7 @@ class PaintingContext extends ClipContext { final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0) ..multiply(transform) - ..translate(-offset.dx, -offset.dy); + ..translateByDouble(-offset.dx, -offset.dy, 0, 1); if (needsCompositing) { final TransformLayer layer = oldLayer ?? TransformLayer(); layer.transform = effectiveTransform; @@ -2049,7 +2049,9 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(child._parent == this); assert(child.attached == attached); assert(child.parentData != null); - _cleanChildRelayoutBoundary(child); + if (!(_isRelayoutBoundary ?? true)) { + child._isRelayoutBoundary = null; + } child.parentData!.detach(); child.parentData = null; child._parent = null; @@ -2337,7 +2339,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge _owner = owner; // If the node was dirtied in some way while unattached, make sure to add // it to the appropriate dirty list now that an owner is available - if (_needsLayout && _relayoutBoundary != null) { + if (_needsLayout && _isRelayoutBoundary != null) { // Don't enter this block if we've never laid out at all; // scheduleInitialLayout() will handle it _needsLayout = false; @@ -2393,33 +2395,35 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge bool _needsLayout = true; - /// The nearest relayout boundary enclosing this render object, if known. - /// - /// When a render object is marked as needing layout, its parent may - /// as a result also need to be marked as needing layout. - /// For details, see [markNeedsLayout]. - /// A render object where relayout does not require relayout of the parent - /// (because its size cannot change on relayout, or because - /// its parent does not use the child's size for its own layout) - /// is a "relayout boundary". - /// - /// This property is set in [layout], and consulted by [markNeedsLayout] in - /// deciding whether to recursively mark the parent as also needing layout. - /// - /// This property is initially null, and becomes null again if this - /// render object is removed from the tree (with [dropChild]); - /// it remains null until the first layout of this render object - /// after it was most recently added to the tree. - /// This property can also be null while an ancestor in the tree is - /// currently doing layout, until this render object itself does layout. - /// - /// When not null, the relayout boundary is either this render object itself - /// or one of its ancestors, and all the render objects in the ancestry chain - /// up through that ancestor have the same [_relayoutBoundary]. - /// Equivalently: when not null, the relayout boundary is either this render - /// object itself or the same as that of its parent. (So [_relayoutBoundary] - /// is one of `null`, `this`, or `parent!._relayoutBoundary!`.) - RenderObject? _relayoutBoundary; + /// Whether this [RenderObject] is a known relayout boundary. + /// + /// A relayout boundary is a [RenderObject] whose parent does not rely on the + /// child [RenderObject]'s size in its own layout algorithm. In other words, + /// if a [RenderObject]'s [performLayout] implementation does not ask the child + /// for its size at all, **the child** is a relayout boundary. + /// + /// The type of "size" is typically defined by the coordinate system a + /// [RenderObject] subclass uses. For instance, [RenderSliver]s produce + /// [SliverGeometry] and [RenderBox]es produce [Size]. A parent [RenderObject] + /// may not read the child's size but still depend on the child's layout (using + /// a [RenderBox] child's baseline location, for example), this flag does not + /// reflect such dependencies and the [RenderObject] subclass must handle those + /// cases in its own implementation. See [RenderBox.markNeedsLayout] for an + /// example. + /// + /// Relayout boundaries enable an important layout optimization: the parent not + /// depending on the size of a child means the child changing size does not + /// affect the layout of the parent. When a relayout boundary is marked as + /// needing layout, its parent does not have to be marked as dirty, hence the + /// name. For details, see [markNeedsLayout]. + /// + /// This flag is typically set in [RenderObject.layout], and consulted by + /// [markNeedsLayout] in deciding whether to recursively mark the parent as + /// also needing layout. + /// + /// The flag is initially set to `null` when [layout] has yet been called, and + /// reset to `null` when the parent drops this child via [dropChild]. + bool? _isRelayoutBoundary; /// Whether [invokeLayoutCallback] for this render object is currently running. bool get debugDoingThisLayoutWithCallback => _doingThisLayoutWithCallback; @@ -2458,20 +2462,19 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge static bool debugCheckingIntrinsics = false; bool _debugRelayoutBoundaryAlreadyMarkedNeedsLayout() { - if (_relayoutBoundary == null) { - // We don't know where our relayout boundary is yet. - return true; - } - RenderObject node = this; - while (node != _relayoutBoundary) { - assert(node._relayoutBoundary == _relayoutBoundary); - assert(node.parent != null); - node = node.parent!; - if ((!node._needsLayout) && (!node._debugDoingThisLayout)) { + for ( + RenderObject? node = this; + node != null && node._isRelayoutBoundary != null; + node = node.parent + ) { + final bool alreadyMarkedNeedsLayout = node._needsLayout || node._debugDoingThisLayout; + if (!alreadyMarkedNeedsLayout) { return false; } + if (node._isRelayoutBoundary!) { + return true; + } } - assert(node._relayoutBoundary == node); return true; } @@ -2519,30 +2522,18 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(_debugRelayoutBoundaryAlreadyMarkedNeedsLayout()); return; } - if (_relayoutBoundary == null) { - _needsLayout = true; - if (parent != null) { - // _relayoutBoundary is cleaned by an ancestor in RenderObject.layout. - // Conservatively mark everything dirty until it reaches the closest - // known relayout boundary. - markParentNeedsLayout(); - } - return; - } - if (_relayoutBoundary != this) { + _needsLayout = true; + if (owner case final PipelineOwner owner? when (_isRelayoutBoundary ?? false)) { + assert(() { + if (debugPrintMarkNeedsLayoutStacks) { + debugPrintStack(label: 'markNeedsLayout() called for $this'); + } + return true; + }()); + owner._nodesNeedingLayout.add(this); + owner.requestVisualUpdate(); + } else if (parent != null) { markParentNeedsLayout(); - } else { - _needsLayout = true; - if (owner != null) { - assert(() { - if (debugPrintMarkNeedsLayoutStacks) { - debugPrintStack(label: 'markNeedsLayout() called for $this'); - } - return true; - }()); - owner!._nodesNeedingLayout.add(this); - owner!.requestVisualUpdate(); - } } } @@ -2581,38 +2572,6 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge markParentNeedsLayout(); } - /// Set [_relayoutBoundary] to null throughout this render object's subtree, - /// stopping at relayout boundaries. - // This is a static method to reduce closure allocation with visitChildren. - static void _cleanChildRelayoutBoundary(RenderObject child) { - if (child._relayoutBoundary != child) { - child.visitChildren(_cleanChildRelayoutBoundary); - child._relayoutBoundary = null; - } - } - - // This is a static method to reduce closure allocation with visitChildren. - static void _propagateRelayoutBoundaryToChild(RenderObject child) { - if (child._relayoutBoundary == child) { - return; - } - final RenderObject? parentRelayoutBoundary = child.parent?._relayoutBoundary; - assert(parentRelayoutBoundary != null); - assert(parentRelayoutBoundary != child._relayoutBoundary); - child._setRelayoutBoundary(parentRelayoutBoundary!); - } - - /// Set [_relayoutBoundary] to [value] throughout this render object's - /// subtree, including this render object but stopping at relayout boundaries - /// thereafter. - void _setRelayoutBoundary(RenderObject value) { - assert(value != _relayoutBoundary); - // This may temporarily break the _relayoutBoundary invariant at children; - // the visitChildren restores the invariant. - _relayoutBoundary = value; - visitChildren(_propagateRelayoutBoundaryToChild); - } - /// Bootstrap the rendering pipeline by scheduling the very first layout. /// /// Requires this render object to be attached and that this render object @@ -2624,8 +2583,8 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge assert(attached); assert(parent == null); assert(!owner!._debugDoingLayout); - assert(_relayoutBoundary == null); - _relayoutBoundary = this; + assert(_isRelayoutBoundary == null); + _isRelayoutBoundary = true; assert(() { _debugCanParentUseSize = false; return true; @@ -2636,7 +2595,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge @pragma('vm:notify-debugger-on-exception') void _layoutWithoutResize() { assert(_needsLayout); - assert(_relayoutBoundary == this || this is RenderObjectWithLayoutCallbackMixin); + assert((_isRelayoutBoundary ?? false) || this is RenderObjectWithLayoutCallbackMixin); RenderObject? debugPreviousActiveLayout; assert(!_debugMutationsLocked); assert(!_doingThisLayoutWithCallback); @@ -2739,14 +2698,12 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge ); assert(!_debugDoingThisResize); assert(!_debugDoingThisLayout); - final bool isRelayoutBoundary = - !parentUsesSize || sizedByParent || constraints.isTight || parent == null; - final RenderObject relayoutBoundary = isRelayoutBoundary ? this : parent!._relayoutBoundary!; assert(() { _debugCanParentUseSize = parentUsesSize; return true; }()); + _isRelayoutBoundary = !parentUsesSize || sizedByParent || constraints.isTight || parent == null; if (!_needsLayout && constraints == _constraints) { assert(() { // in case parentUsesSize changed since the last invocation, set size @@ -2761,11 +2718,6 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge _debugDoingThisResize = false; return true; }()); - - if (relayoutBoundary != _relayoutBoundary) { - _setRelayoutBoundary(relayoutBoundary); - } - if (!kReleaseMode && debugProfileLayoutsEnabled) { FlutterTimeline.finishSync(); } @@ -2773,14 +2725,6 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge } _constraints = constraints; - if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) { - // The local relayout boundary has changed, must notify children in case - // they also need updating. Otherwise, they will be confused about what - // their actual relayout boundary is later. - visitChildren(_cleanChildRelayoutBoundary); - } - _relayoutBoundary = relayoutBoundary; - assert(!_debugMutationsLocked); assert(!_doingThisLayoutWithCallback); assert(() { @@ -3901,13 +3845,20 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge header += ' DISPOSED'; return header; } - if (_relayoutBoundary != null && _relayoutBoundary != this) { - int count = 1; - RenderObject? target = parent; - while (target != null && target != _relayoutBoundary) { - target = target.parent; - count += 1; + + int count = 0; + for ( + RenderObject? node = this; + node != null && !(node._isRelayoutBoundary ?? false); + node = node.parent + ) { + if (node._isRelayoutBoundary == null) { + count = -1; + break; } + count += 1; + } + if (count > 0) { header += ' relayoutBoundary=up$count'; } if (_needsLayout) { @@ -4872,19 +4823,19 @@ typedef _MergeUpAndSiblingMergeGroups = /// Merge all fragments from [mergeUp] and decide which [_RenderObjectSemantics] /// should form a node, i.e. [shouldFormSemanticsNode] is true. Stores the /// [_RenderObjectSemantics] that should form a node with elevation adjustments -/// into [_childrenAndElevationAdjustments]. +/// into [_children]. /// -/// At this point, walking the [_childrenAndElevationAdjustments] forms a tree +/// At this point, walking the [_children] forms a tree /// that exactly resemble the resulting semantics node tree. /// /// ### Phase 3 /// -/// Walks the [_childrenAndElevationAdjustments] and calculate their +/// Walks the [_children] and calculate their /// [_SemanticsGeometry] based on renderObject relationship. /// /// ### Phase 4 /// -/// Walks the [_childrenAndElevationAdjustments] and produce semantics node for +/// Walks the [_children] and produce semantics node for /// each [_RenderObjectSemantics] plus the sibling nodes. /// /// Phase 2, 3, 4 each depends on previous step to finished updating the the @@ -4899,7 +4850,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM bool _hasSiblingConflict = false; bool? _blocksPreviousSibling; - double elevationAdjustment = 0.0; + // TODO(chunhtai): Figure out what to do when incomplete fragments are asked // to form a semantics node. // @@ -4936,10 +4887,9 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Fragments that will merge up to parent rendering object semantics. final List<_SemanticsFragment> mergeUp = <_SemanticsFragment>[]; - /// A map that record immediate child [_RenderObjectSemantics]s that will form - /// semantics nodes with their elevation adjustments. - final Map<_RenderObjectSemantics, double> _childrenAndElevationAdjustments = - <_RenderObjectSemantics, double>{}; + /// A list to store immediate child [_RenderObjectSemantics]s that will form + /// semantics nodes. + final List<_RenderObjectSemantics> _children = <_RenderObjectSemantics>[]; /// Merge groups that will form additional sibling nodes. final List> siblingMergeGroups = >[]; @@ -5056,7 +5006,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Updates the [parentData] for the [_RenderObjectSemantics]s in the /// rendering subtree and forms a [_RenderObjectSemantics] tree where children - /// are stored in [_childrenAndElevationAdjustments]. + /// are stored in [_children]. /// /// This method does the the phase 1 and 2 of the four phases documented on /// [_RenderObjectSemantics]. @@ -5072,7 +5022,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Merge all fragments from [mergeUp] and decide which [_RenderObjectSemantics] /// should form a node. i.e. [shouldFormSemanticsNode] is true. Stores the /// [_RenderObjectSemantics] that should form a node with elevation adjustments - /// into [_childrenAndElevationAdjustments]. + /// into [_children]. void updateChildren() { assert(parentData != null || isRoot, 'parent data can only be null for root rendering object'); configProvider.reset(); @@ -5106,7 +5056,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM siblingMergeGroups.addAll(result.$2); // Construct tree for nodes that will form semantics nodes. - _childrenAndElevationAdjustments.clear(); + _children.clear(); if (contributesToSemanticsTree) { _marksConflictsInMergeGroup(mergeUp, isMergeUp: true); siblingMergeGroups.forEach(_marksConflictsInMergeGroup); @@ -5126,16 +5076,9 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM in result.$1.whereType<_RenderObjectSemantics>()) { assert(childSemantics.contributesToSemanticsTree); if (childSemantics.shouldFormSemanticsNode) { - _childrenAndElevationAdjustments[childSemantics] = 0.0; + _children.add(childSemantics); } else { - final Map<_RenderObjectSemantics, double> passUpChildren = - childSemantics._childrenAndElevationAdjustments; - for (final _RenderObjectSemantics passUpChild in passUpChildren.keys) { - final double passUpElevationAdjustment = - passUpChildren[passUpChild]! + childSemantics.configProvider.original.elevation; - _childrenAndElevationAdjustments[passUpChild] = passUpElevationAdjustment; - passUpChild.elevationAdjustment = passUpElevationAdjustment; - } + _children.addAll(childSemantics._children); siblingMergeGroups.addAll(childSemantics.siblingMergeGroups); } } @@ -5315,7 +5258,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM } /// Updates the [geometry] for this [_RenderObjectSemantics]s and its subtree - /// in [_childrenAndElevationAdjustments]. + /// in [_children]. /// /// This method does the the phase 3 of the four phases documented on /// [_RenderObjectSemantics]. @@ -5336,7 +5279,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM void _updateChildGeometry() { assert(geometry != null); - for (final _RenderObjectSemantics child in _childrenAndElevationAdjustments.keys) { + for (final _RenderObjectSemantics child in _children) { final _SemanticsGeometry childGeometry = _SemanticsGeometry.computeChildGeometry( parentPaintClipRect: geometry!.paintClipRect, parentSemanticsClipRect: geometry!.semanticsClipRect, @@ -5385,7 +5328,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM // update for semantics nodes generated in this render object semantics. // // Therefore, we only need to update the subtree. - _buildSemanticsSubtree(usedSemanticsIds: {}, elevationAdjustment: 0.0); + _buildSemanticsSubtree(usedSemanticsIds: {}); } } @@ -5435,11 +5378,10 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Builds the semantics subtree under the [cachedSemanticsNode]. void _buildSemanticsSubtree({ required Set usedSemanticsIds, - required double elevationAdjustment, List? semanticsNodes, }) { final List children = []; - for (final _RenderObjectSemantics child in _childrenAndElevationAdjustments.keys) { + for (final _RenderObjectSemantics child in _children) { assert(child.shouldFormSemanticsNode); // Cached semantics node may be part of sibling merging group prior // to this update. In this case, the semantics node may continue to @@ -5474,11 +5416,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM _updateSemanticsNodeGeometry(); _mergeSiblingGroup(usedSemanticsIds); - _buildSemanticsSubtree( - semanticsNodes: semanticsNodes, - usedSemanticsIds: usedSemanticsIds, - elevationAdjustment: elevationAdjustment, - ); + _buildSemanticsSubtree(semanticsNodes: semanticsNodes, usedSemanticsIds: usedSemanticsIds); } SemanticsNode _createSemanticsNode() { @@ -5556,12 +5494,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM void _updateSemanticsNodeGeometry() { final SemanticsNode node = cachedSemanticsNode!; final _SemanticsGeometry nodeGeometry = geometry!; - node.elevationAdjustment = elevationAdjustment; - if (elevationAdjustment != 0.0) { - configProvider.updateConfig((SemanticsConfiguration config) { - config.elevation = configProvider.original.elevation + elevationAdjustment; - }); - } final bool isSemanticsHidden = configProvider.original.isHidden || (!(parentData?.mergeIntoParent ?? false) && nodeGeometry.hidden); @@ -5661,7 +5593,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM node._semantics.geometry = null; node._semantics.parentData = null; node._semantics._blocksPreviousSibling = null; - node._semantics.elevationAdjustment = 0.0; // Since this node is a semantics boundary, the produced sibling nodes will // be attached to the parent semantics boundary. Thus, these sibling nodes // will not be carried to the next loop. @@ -5737,7 +5668,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Removes any cache stored in this object as if it is newly created. void clear() { built = false; - elevationAdjustment = 0.0; cachedSemanticsNode = null; parentData = null; geometry = null; @@ -5745,7 +5675,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM _containsIncompleteFragment = false; mergeUp.clear(); siblingMergeGroups.clear(); - _childrenAndElevationAdjustments.clear(); + _children.clear(); semanticsNodes.clear(); configProvider.clear(); } diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 24edfedf3b70f..3f5cea89e5aa0 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -248,7 +248,7 @@ mixin RenderInlineChildrenContainerDefaults if (offset == null) { transform.setZero(); } else { - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } } diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 9e927b9df3e27..717d1adee7ee8 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -2048,12 +2048,6 @@ abstract class _RenderPhysicalModelBase extends _RenderCustomClip { markNeedsPaint(); } - @override - void describeSemanticsConfiguration(SemanticsConfiguration config) { - super.describeSemanticsConfiguration(config); - config.elevation = elevation; - } - @override void debugFillProperties(DiagnosticPropertiesBuilder description) { super.debugFillProperties(description); @@ -2612,14 +2606,14 @@ class RenderTransform extends RenderProxyBox { /// Concatenates a translation by (x, y, z) into the transform. void translate(double x, [double y = 0.0, double z = 0.0]) { - _transform!.translate(x, y, z); + _transform!.translateByDouble(x, y, z, 1); markNeedsPaint(); markNeedsSemanticsUpdate(); } /// Concatenates a scale into the transform. void scale(double x, [double? y, double? z]) { - _transform!.scale(x, y, z); + _transform!.scaleByDouble(x, y ?? x, z ?? x, 1); markNeedsPaint(); markNeedsSemanticsUpdate(); } @@ -2631,19 +2625,19 @@ class RenderTransform extends RenderProxyBox { } final Matrix4 result = Matrix4.identity(); if (_origin != null) { - result.translate(_origin!.dx, _origin!.dy); + result.translateByDouble(_origin!.dx, _origin!.dy, 0, 1); } Offset? translation; if (resolvedAlignment != null) { translation = resolvedAlignment.alongSize(size); - result.translate(translation.dx, translation.dy); + result.translateByDouble(translation.dx, translation.dy, 0, 1); } result.multiply(_transform!); if (resolvedAlignment != null) { - result.translate(-translation!.dx, -translation.dy); + result.translateByDouble(-translation!.dx, -translation.dy, 0, 1); } if (_origin != null) { - result.translate(-_origin!.dx, -_origin!.dy); + result.translateByDouble(-_origin!.dx, -_origin!.dy, 0, 1); } return result; } @@ -2698,7 +2692,7 @@ class RenderTransform extends RenderProxyBox { final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0) ..multiply(transform) - ..translate(-offset.dx, -offset.dy); + ..translateByDouble(-offset.dx, -offset.dy, 0, 1); final ui.ImageFilter filter = ui.ImageFilter.matrix( effectiveTransform.storage, filterQuality: filterQuality!, @@ -2917,8 +2911,8 @@ class RenderFittedBox extends RenderProxyBox { assert(scaleX.isFinite && scaleY.isFinite); _transform = Matrix4.translationValues(destinationRect.left, destinationRect.top, 0.0) - ..scale(scaleX, scaleY, 1.0) - ..translate(-sourceRect.left, -sourceRect.top); + ..scaleByDouble(scaleX, scaleY, 1.0, 1) + ..translateByDouble(-sourceRect.left, -sourceRect.top, 0, 1); assert(_transform!.storage.every((double value) => value.isFinite)); } } @@ -3078,7 +3072,7 @@ class RenderFractionalTranslation extends RenderProxyBox { @override void applyPaintTransform(RenderBox child, Matrix4 transform) { - transform.translate(translation.dx * size.width, translation.dy * size.height); + transform.translateByDouble(translation.dx * size.width, translation.dy * size.height, 0, 1); } @override diff --git a/packages/flutter/lib/src/rendering/rotated_box.dart b/packages/flutter/lib/src/rendering/rotated_box.dart index cf8f5e725f975..62fc9dbd2e059 100644 --- a/packages/flutter/lib/src/rendering/rotated_box.dart +++ b/packages/flutter/lib/src/rendering/rotated_box.dart @@ -8,7 +8,7 @@ library; import 'dart:math' as math; import 'package:flutter/foundation.dart'; -import 'package:vector_math/vector_math_64.dart'; +import 'package:vector_math/vector_math_64.dart' show Matrix4; import 'box.dart'; import 'layer.dart'; @@ -92,9 +92,9 @@ class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin('rect', rect, showName: false)); properties.add(TransformProperty('transform', transform, showName: false, defaultValue: null)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0)); - properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0)); final List actionSummary = [ for (final SemanticsAction action in SemanticsAction.values) if ((actions & action.index) != 0) action.name, @@ -1119,8 +1100,6 @@ class SemanticsData with Diagnosticable { other.maxValueLength == maxValueLength && other.currentValueLength == currentValueLength && other.transform == transform && - other.elevation == elevation && - other.thickness == thickness && other.headingLevel == headingLevel && other.linkUrl == linkUrl && other.role == role && @@ -1155,8 +1134,6 @@ class SemanticsData with Diagnosticable { maxValueLength, currentValueLength, transform, - elevation, - thickness, headingLevel, linkUrl, customSemanticsActionIds == null ? null : Object.hashAll(customSemanticsActionIds!), @@ -2373,27 +2350,6 @@ class SemanticsNode with DiagnosticableTreeMixin { /// If this rect is null [parentSemanticsClipRect] also has to be null. Rect? parentPaintClipRect; - /// The elevation adjustment that the parent imposes on this node. - /// - /// The [elevation] property is relative to the elevation of the parent - /// [SemanticsNode]. However, as [SemanticsConfiguration]s from various - /// ascending [RenderObject]s are merged into each other to form that - /// [SemanticsNode] the parent’s elevation may change. This requires an - /// adjustment of the child’s relative elevation which is represented by this - /// value. - /// - /// The value is rarely accessed directly. Instead, for most use cases the - /// [elevation] value should be used, which includes this adjustment. - /// - /// See also: - /// - /// * [elevation], the actual elevation of this [SemanticsNode]. - @Deprecated( - 'This was a cache for internal calculations and is no longer needed. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double? elevationAdjustment; - /// The index of this node within the parent's list of semantic children. /// /// This includes all semantic nodes, not just those currently in the @@ -2802,8 +2758,6 @@ class SemanticsNode with DiagnosticableTreeMixin { bool _isDifferentFromCurrentSemanticAnnotation(SemanticsConfiguration config) { return _attributedLabel != config.attributedLabel || _attributedHint != config.attributedHint || - _elevation != config.elevation || - _thickness != config.thickness || _attributedValue != config.attributedValue || _attributedIncreasedValue != config.attributedIncreasedValue || _attributedDecreasedValue != config.attributedDecreasedValue || @@ -2964,75 +2918,6 @@ class SemanticsNode with DiagnosticableTreeMixin { String get tooltip => _tooltip; String _tooltip = _kEmptyConfig.tooltip; - /// The elevation along the z-axis at which the [rect] of this [SemanticsNode] - /// is located above its parent. - /// - /// The value is relative to the parent's [elevation]. The sum of the - /// [elevation]s of all ancestor node plus this value determines the absolute - /// elevation of this [SemanticsNode]. - /// - /// See also: - /// - /// * [thickness], which describes how much space in z-direction this - /// [SemanticsNode] occupies starting at this [elevation]. - /// * [elevationAdjustment], which has been used to calculate this value. - @Deprecated( - 'This was a feature added for 3D rendering, but the feature was deprecated. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double get elevation => _elevation; - double _elevation = _kEmptyConfig.elevation; - - /// Describes how much space the [SemanticsNode] takes up along the z-axis. - /// - /// A [SemanticsNode] represents multiple [RenderObject]s, which can be - /// located at various elevations in 3D. The [thickness] is the difference - /// between the absolute elevations of the lowest and highest [RenderObject] - /// represented by this [SemanticsNode]. In other words, the thickness - /// describes how high the box is that this [SemanticsNode] occupies in three - /// dimensional space. The two other dimensions are defined by [rect]. - /// - /// {@tool snippet} - /// The following code stacks three [PhysicalModel]s on top of each other - /// separated by non-zero elevations. - /// - /// [PhysicalModel] C is elevated 10.0 above [PhysicalModel] B, which in turn - /// is elevated 5.0 above [PhysicalModel] A. The side view of this - /// constellation looks as follows: - /// - /// ![A diagram illustrating the elevations of three PhysicalModels and their - /// corresponding SemanticsNodes.](https://flutter.github.io/assets-for-api-docs/assets/semantics/SemanticsNode.thickness.png) - /// - /// In this example the [RenderObject]s for [PhysicalModel] C and B share one - /// [SemanticsNode] Y. Given the elevations of those [RenderObject]s, this - /// [SemanticsNode] has a [thickness] of 10.0 and an elevation of 5.0 over - /// its parent [SemanticsNode] X. - /// ```dart - /// PhysicalModel( // A - /// color: Colors.amber, - /// child: Semantics( - /// explicitChildNodes: true, - /// child: const PhysicalModel( // B - /// color: Colors.brown, - /// elevation: 5.0, - /// child: PhysicalModel( // C - /// color: Colors.cyan, - /// elevation: 10.0, - /// child: Placeholder(), - /// ), - /// ), - /// ), - /// ) - /// ``` - /// {@end-tool} - /// - /// See also: - /// - /// * [elevation], which describes the elevation of the box defined by - /// [thickness] and [rect] relative to the parent of this [SemanticsNode]. - double get thickness => _thickness; - double _thickness = _kEmptyConfig.thickness; - /// Provides hint values which override the default hints on supported /// platforms. SemanticsHintOverrides? get hintOverrides => _hintOverrides; @@ -3229,8 +3114,6 @@ class SemanticsNode with DiagnosticableTreeMixin { _attributedHint = config.attributedHint; _tooltip = config.tooltip; _hintOverrides = config.hintOverrides; - _elevation = config.elevation; - _thickness = config.thickness; _flags = config._flags; _textDirection = config.textDirection; _sortKey = config.sortKey; @@ -3304,8 +3187,6 @@ class SemanticsNode with DiagnosticableTreeMixin { int? maxValueLength = _maxValueLength; int? currentValueLength = _currentValueLength; int headingLevel = _headingLevel; - final double elevation = _elevation; - double thickness = _thickness; Uri? linkUrl = _linkUrl; SemanticsRole role = _role; Set? controlsNodes = _controlsNodes; @@ -3410,8 +3291,6 @@ class SemanticsNode with DiagnosticableTreeMixin { otherTextDirection: node._textDirection, ); - thickness = math.max(thickness, node._thickness + node._elevation); - if (controlsNodes == null) { controlsNodes = node._controlsNodes; } else if (node._controlsNodes != null) { @@ -3446,8 +3325,6 @@ class SemanticsNode with DiagnosticableTreeMixin { textDirection: textDirection, rect: rect, transform: transform, - elevation: elevation, - thickness: thickness, tags: mergedTags, textSelection: textSelection, scrollChildCount: scrollChildCount, @@ -3542,8 +3419,6 @@ class SemanticsNode with DiagnosticableTreeMixin { scrollExtentMax: data.scrollExtentMax ?? double.nan, scrollExtentMin: data.scrollExtentMin ?? double.nan, transform: data.transform?.storage ?? _kIdentityTransform, - elevation: data.elevation, - thickness: data.thickness, childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: customSemanticsActionIds ?? _kEmptyCustomSemanticsActionsList, @@ -3741,8 +3616,6 @@ class SemanticsNode with DiagnosticableTreeMixin { properties.add(DoubleProperty('scrollPosition', scrollPosition, defaultValue: null)); properties.add(DoubleProperty('scrollExtentMax', scrollExtentMax, defaultValue: null)); properties.add(IntProperty('indexInParent', indexInParent, defaultValue: null)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0)); - properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0)); properties.add(IntProperty('headingLevel', _headingLevel, defaultValue: 0)); if (_inputType != SemanticsInputType.none) { properties.add(EnumProperty('inputType', _inputType)); @@ -5302,40 +5175,6 @@ class SemanticsConfiguration { _hasBeenAnnotated = true; } - /// The elevation in z-direction at which the owning [RenderObject] is - /// located relative to its parent. - @Deprecated( - 'This was a feature added for 3D rendering, but the feature was deprecated. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double get elevation => _elevation; - double _elevation = 0.0; - set elevation(double value) { - assert(value >= 0.0); - if (value == _elevation) { - return; - } - _elevation = value; - _hasBeenAnnotated = true; - } - - /// The extend that the owning [RenderObject] occupies in z-direction starting - /// at [elevation]. - /// - /// It's extremely rare to set this value directly. Instead, it is calculated - /// implicitly when other [SemanticsConfiguration]s are merged into this one - /// via [absorb]. - double get thickness => _thickness; - double _thickness = 0.0; - set thickness(double value) { - assert(value >= 0.0); - if (value == _thickness) { - return; - } - _thickness = value; - _hasBeenAnnotated = true; - } - /// Whether the semantics node is the root of a subtree for which values /// should be announced. /// @@ -5927,8 +5766,6 @@ class SemanticsConfiguration { _tooltip = child._tooltip; } - _thickness = math.max(_thickness, child._thickness + child._elevation); - if (_controlsNodes == null) { _controlsNodes = child._controlsNodes; } else if (child._controlsNodes != null) { @@ -5965,8 +5802,6 @@ class SemanticsConfiguration { .._attributedHint = _attributedHint .._hintOverrides = _hintOverrides .._tooltip = _tooltip - .._elevation = _elevation - .._thickness = _thickness .._flags = _flags .._tagsForChildren = _tagsForChildren .._textSelection = _textSelection diff --git a/packages/flutter/lib/src/widget_previews/widget_previews.dart b/packages/flutter/lib/src/widget_previews/widget_previews.dart index 66d6279ad0f9c..f2352ed8a9996 100644 --- a/packages/flutter/lib/src/widget_previews/widget_previews.dart +++ b/packages/flutter/lib/src/widget_previews/widget_previews.dart @@ -16,6 +16,9 @@ typedef PreviewTheme = PreviewThemeData Function(); /// Signature for callbacks that wrap a [Widget] with another [Widget] when creating a [Preview]. typedef WidgetWrapper = Widget Function(Widget); +/// Signature for callbacks that build localization data used when creating a [Preview]. +typedef PreviewLocalizations = PreviewLocalizationsData Function(); + /// Annotation used to mark functions that return a widget preview. /// /// NOTE: this interface is not stable and **will change**. @@ -68,6 +71,7 @@ base class Preview { this.wrapper, this.theme, this.brightness, + this.localizations, }); /// A description to be displayed alongside the preview. @@ -114,6 +118,79 @@ base class Preview { /// /// If not provided, the current system default brightness will be used. final Brightness? brightness; + + /// A callback to return a localization configuration to be applied to the + /// previewed [Widget]. + /// + /// Note: this must be a reference to a static, public function defined as + /// either a top-level function or static member in a class. + final PreviewLocalizations? localizations; +} + +/// A collection of localization objects and callbacks for use in widget previews. +base class PreviewLocalizationsData { + /// Creates a collection of localization objects and callbacks for use in + /// widget previews. + const PreviewLocalizationsData({ + this.locale, + this.supportedLocales = const [Locale('en', 'US')], + this.localizationsDelegates, + this.localeListResolutionCallback, + this.localeResolutionCallback, + }); + + /// {@macro flutter.widgets.widgetsApp.locale} + /// + /// See also: + /// + /// * [localeResolutionCallback], which can override the default + /// [supportedLocales] matching algorithm. + /// * [localizationsDelegates], which collectively define all of the localized + /// resources used by this preview. + final Locale? locale; + + /// {@macro flutter.widgets.widgetsApp.supportedLocales} + /// + /// See also: + /// + /// * [localeResolutionCallback], an app callback that resolves the app's locale + /// when the device's locale changes. + /// * [localizationsDelegates], which collectively define all of the localized + /// resources used by this app. + /// * [basicLocaleListResolution], the default locale resolution algorithm. + final List supportedLocales; + + /// The delegates for this preview's [Localizations] widget. + /// + /// The delegates collectively define all of the localized resources + /// for this preview's [Localizations] widget. + final Iterable>? localizationsDelegates; + + /// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback} + /// + /// This callback considers the entire list of preferred locales. + /// + /// This algorithm should be able to handle a null or empty list of preferred locales, + /// which indicates Flutter has not yet received locale information from the platform. + /// + /// See also: + /// + /// * [basicLocaleListResolution], the default locale resolution algorithm. + final LocaleListResolutionCallback? localeListResolutionCallback; + + /// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback} + /// + /// This callback considers only the default locale, which is the first locale + /// in the preferred locales list. It is preferred to set [localeListResolutionCallback] + /// over [localeResolutionCallback] as it provides the full preferred locales list. + /// + /// This algorithm should be able to handle a null locale, which indicates + /// Flutter has not yet received locale information from the platform. + /// + /// See also: + /// + /// * [basicLocaleListResolution], the default locale resolution algorithm. + final LocaleResolutionCallback? localeResolutionCallback; } /// A collection of [ThemeData] and [CupertinoThemeData] instances for use in diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 0d9cc21d328f9..7c7f3278489f7 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -39,6 +39,7 @@ import 'shortcuts.dart'; import 'tap_region.dart'; import 'text.dart'; import 'title.dart'; +import 'transitions.dart'; import 'value_listenable_builder.dart'; import 'widget_inspector.dart'; @@ -1459,10 +1460,6 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { void initState() { super.initState(); _updateRouting(); - _locale = _resolveLocales( - WidgetsBinding.instance.platformDispatcher.locales, - widget.supportedLocales, - ); WidgetsBinding.instance.addObserver(this); _appLifecycleState = WidgetsBinding.instance.lifecycleState; } @@ -1471,12 +1468,14 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { void didUpdateWidget(WidgetsApp oldWidget) { super.didUpdateWidget(oldWidget); _updateRouting(oldWidget: oldWidget); + _updateLocalizations(oldWidget: oldWidget); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _defaultRouteInformationProvider?.dispose(); + _localizationsResolver.dispose(); super.dispose(); } @@ -1643,118 +1642,26 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { } // LOCALIZATION - - /// This is the resolved locale, and is one of the supportedLocales. - Locale? _locale; - - Locale _resolveLocales(List? preferredLocales, Iterable supportedLocales) { - // Attempt to use localeListResolutionCallback. - if (widget.localeListResolutionCallback != null) { - final Locale? locale = widget.localeListResolutionCallback!( - preferredLocales, - widget.supportedLocales, - ); - if (locale != null) { - return locale; - } - } - // localeListResolutionCallback failed, falling back to localeResolutionCallback. - if (widget.localeResolutionCallback != null) { - final Locale? locale = widget.localeResolutionCallback!( - preferredLocales != null && preferredLocales.isNotEmpty ? preferredLocales.first : null, - widget.supportedLocales, - ); - if (locale != null) { - return locale; - } - } - // Both callbacks failed, falling back to default algorithm. - return basicLocaleListResolution(preferredLocales, supportedLocales); - } - - @override - void didChangeLocales(List? locales) { - final Locale newLocale = _resolveLocales(locales, widget.supportedLocales); - if (newLocale != _locale) { - setState(() { - _locale = newLocale; - }); - } - } - - // Combine the Localizations for Widgets with the ones contributed - // by the localizationsDelegates parameter, if any. Only the first delegate - // of a particular LocalizationsDelegate.type is loaded so the - // localizationsDelegate parameter can be used to override - // WidgetsLocalizations.delegate. - Iterable> get _localizationsDelegates { - return >[ - if (widget.localizationsDelegates != null) ...widget.localizationsDelegates!, - DefaultWidgetsLocalizations.delegate, - ]; + late final LocalizationsResolver _localizationsResolver = LocalizationsResolver( + locale: widget.locale, + localeListResolutionCallback: widget.localeListResolutionCallback, + localeResolutionCallback: widget.localeResolutionCallback, + localizationsDelegates: widget.localizationsDelegates, + supportedLocales: widget.supportedLocales, + ); + + void _updateLocalizations({WidgetsApp? oldWidget}) { + _localizationsResolver.update( + locale: widget.locale, + localeListResolutionCallback: widget.localeListResolutionCallback, + localeResolutionCallback: widget.localeResolutionCallback, + supportedLocales: widget.supportedLocales, + localizationsDelegates: widget.localizationsDelegates, + ); } // BUILDER - bool _debugCheckLocalizations(Locale appLocale) { - assert(() { - final Set unsupportedTypes = - _localizationsDelegates - .map((LocalizationsDelegate delegate) => delegate.type) - .toSet(); - for (final LocalizationsDelegate delegate in _localizationsDelegates) { - if (!unsupportedTypes.contains(delegate.type)) { - continue; - } - if (delegate.isSupported(appLocale)) { - unsupportedTypes.remove(delegate.type); - } - } - if (unsupportedTypes.isEmpty) { - return true; - } - - FlutterError.reportError( - FlutterErrorDetails( - exception: - "Warning: This application's locale, $appLocale, is not supported by all of its localization delegates.", - library: 'widgets', - informationCollector: - () => [ - for (final Type unsupportedType in unsupportedTypes) - ErrorDescription( - '• A $unsupportedType delegate that supports the $appLocale locale was not found.', - ), - ErrorSpacer(), - if (unsupportedTypes.length == 1 && - unsupportedTypes.single.toString() == 'CupertinoLocalizations') - // We previously explicitly avoided checking for this class so it's not uncommon for applications - // to have omitted importing the required delegate. - ...[ - ErrorHint( - 'If the application is built using GlobalMaterialLocalizations.delegate, consider using ' - 'GlobalMaterialLocalizations.delegates (plural) instead, as that will automatically declare ' - 'the appropriate Cupertino localizations.', - ), - ErrorSpacer(), - ], - ErrorHint( - 'The declared supported locales for this app are: ${widget.supportedLocales.join(", ")}', - ), - ErrorSpacer(), - ErrorDescription( - 'See https://flutter.dev/to/internationalization/ for more ' - "information about configuring an app's locale, supportedLocales, " - 'and localizationsDelegates parameters.', - ), - ], - ), - ); - return true; - }()); - return true; - } - @override Widget build(BuildContext context) { Widget? routing; @@ -1870,13 +1777,6 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { title = Title(title: widget.title ?? '', color: widget.color.withOpacity(1.0), child: result); } - final Locale appLocale = - widget.locale != null - ? _resolveLocales([widget.locale!], widget.supportedLocales) - : _locale!; - - assert(_debugCheckLocalizations(appLocale)); - return RootRestorationScope( restorationId: widget.restorationScopeId, child: SharedAppData( @@ -1902,10 +1802,15 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { policy: ReadingOrderTraversalPolicy(), child: TapRegionSurface( child: ShortcutRegistrar( - child: Localizations( - locale: appLocale, - delegates: _localizationsDelegates.toList(), - child: title ?? result, + child: ListenableBuilder( + listenable: _localizationsResolver, + builder: (BuildContext context, _) { + return Localizations( + locale: _localizationsResolver.locale, + delegates: _localizationsResolver.localizationsDelegates.toList(), + child: title ?? result, + ); + }, ), ), ), diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index 47b9679b672d3..7bdf9b38d404a 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -542,7 +542,8 @@ class _RawAutocompleteState extends State> OptionsViewOpenDirection.down => overlayRectInField.bottom - optionsViewBoundingBox.height, }; - final Matrix4 transform = layoutInfo.childPaintTransform.clone()..translate(0.0, originY); + final Matrix4 transform = + layoutInfo.childPaintTransform.clone()..translateByDouble(0.0, originY, 0, 1); final Widget child = Builder( builder: (BuildContext context) => widget.optionsViewBuilder(context, _select, _options), ); diff --git a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart index 4965e1b5d9376..0c93135a4baad 100644 --- a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart +++ b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart @@ -27,13 +27,23 @@ import 'sliver.dart'; /// /// To send these notifications, consider using [AutomaticKeepAliveClientMixin]. /// +/// The [SliverChildBuilderDelegate] and [SliverChildListDelegate] delegates, +/// used with [SliverList] and [SliverGrid], as well as the scroll view +/// counterparts [ListView] and [GridView], have an `addAutomaticKeepAlives` +/// feature, which is enabled by default. This feature inserts +/// [AutomaticKeepAlive] widgets around each child, which in turn configure +/// [KeepAlive] widgets in response to [KeepAliveNotification]s. +/// +/// The same `addAutomaticKeepAlives` feature is supported by +/// [TwoDimensionalChildBuilderDelegate] and [TwoDimensionalChildListDelegate]. +/// /// {@tool dartpad} /// This sample demonstrates how to use the [AutomaticKeepAlive] widget in /// combination with the [AutomaticKeepAliveClientMixin] to selectively preserve /// the state of individual items in a scrollable list. /// /// Normally, widgets in a lazily built list like [ListView.builder] are -/// disposed of when they leave the visible area to save resources. This means +/// disposed of when they leave the visible area to maintain performance. This means /// that any state inside a [StatefulWidget] would be lost unless explicitly /// preserved. /// @@ -50,6 +60,13 @@ import 'sliver.dart'; /// ** See code in examples/api/lib/widgets/keep_alive/automatic_keep_alive.0.dart ** /// {@end-tool} /// +/// See also: +/// +/// * [AutomaticKeepAliveClientMixin], which is a mixin with convenience +/// methods for clients of [AutomaticKeepAlive]. Used with [State] +/// subclasses. +/// * [KeepAlive] which marks a child as needing to stay alive even when it's +/// in a lazy list that would otherwise remove it. class AutomaticKeepAlive extends StatefulWidget { /// Creates a widget that listens to [KeepAliveNotification]s and maintains a /// [KeepAlive] widget appropriately. @@ -354,8 +371,19 @@ class KeepAliveHandle extends ChangeNotifier { } } -/// A mixin with convenience methods for clients of [AutomaticKeepAlive]. Used -/// with [State] subclasses. +/// A mixin with convenience methods for clients of [AutomaticKeepAlive]. It is used +/// with [State] subclasses to manage keep-alive behavior in lazily built lists. +/// +/// This mixin simplifies interaction with [AutomaticKeepAlive] by automatically +/// sending [KeepAliveNotification]s when necessary. Subclasses must implement +/// [wantKeepAlive] to indicate whether the widget should be kept alive and call +/// [updateKeepAlive] whenever its value changes. +/// +/// The mixin internally manages a [KeepAliveHandle], which is used to notify +/// the nearest [AutomaticKeepAlive] ancestor of changes in keep-alive +/// requirements. [AutomaticKeepAlive] listens for [KeepAliveNotification]s sent +/// by this mixin and dynamically wraps the subtree in a [KeepAlive] widget to +/// preserve its state when it is no longer visible in the viewport. /// /// Subclasses must implement [wantKeepAlive], and their [build] methods must /// call `super.build` (though the return value should be ignored). @@ -366,9 +394,20 @@ class KeepAliveHandle extends ChangeNotifier { /// The type argument `T` is the type of the [StatefulWidget] subclass of the /// [State] into which this class is being mixed. /// +/// The [SliverChildBuilderDelegate] and [SliverChildListDelegate] delegates, +/// used with [SliverList] and [SliverGrid], as well as the scroll view +/// counterparts [ListView] and [GridView], have an `addAutomaticKeepAlives` +/// feature, which is enabled by default. This feature inserts +/// [AutomaticKeepAlive] widgets around each child, which in turn configure +/// [KeepAlive] widgets in response to [KeepAliveNotification]s. +/// +/// The same `addAutomaticKeepAlives` feature is supported by +/// [TwoDimensionalChildBuilderDelegate] and [TwoDimensionalChildListDelegate]. +/// /// {@tool dartpad} -/// This example demonstrates how to use the [AutomaticKeepAliveClientMixin] -/// to keep the state of a widget alive even when it is scrolled out of view. +/// This example demonstrates how to use the +/// [AutomaticKeepAliveClientMixin] to keep the state of a widget alive even +/// when it is scrolled out of view. /// /// ** See code in examples/api/lib/widgets/keep_alive/automatic_keep_alive_client_mixin.0.dart ** /// {@end-tool} @@ -377,6 +416,8 @@ class KeepAliveHandle extends ChangeNotifier { /// /// * [AutomaticKeepAlive], which listens to messages from this mixin. /// * [KeepAliveNotification], the notifications sent by this mixin. +/// * [KeepAlive] which marks a child as needing to stay alive even when it's +/// in a lazy list that would otherwise remove it. @optionalTypeArgs mixin AutomaticKeepAliveClientMixin on State { KeepAliveHandle? _keepAliveHandle; diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 6315f6843ebd6..1a96c8ffc389e 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -5574,7 +5574,10 @@ class EditableTextState extends State ), ), ScrollToDocumentBoundaryIntent: _makeOverridable( - CallbackAction(onInvoke: _scrollToDocumentBoundary), + _WebComposingDisablingCallbackAction( + this, + onInvoke: _scrollToDocumentBoundary, + ), ), ScrollIntent: CallbackAction(onInvoke: _scroll), @@ -6482,7 +6485,13 @@ class _UpdateTextSelectionAction } @override - bool get isActionEnabled => state._value.selection.isValid; + bool get isActionEnabled { + if (kIsWeb && state.widget.selectionEnabled && state._value.composing.isValid) { + return false; + } + + return state._value.selection.isValid; + } } class _UpdateTextSelectionVerticallyAction @@ -6562,7 +6571,28 @@ class _UpdateTextSelectionVerticallyAction state._value.selection.isValid; + bool get isActionEnabled { + if (kIsWeb && state.widget.selectionEnabled && state._value.composing.isValid) { + return false; + } + + return state._value.selection.isValid; + } +} + +class _WebComposingDisablingCallbackAction extends CallbackAction { + _WebComposingDisablingCallbackAction(this.state, {required super.onInvoke}); + + final EditableTextState state; + + @override + bool get isActionEnabled { + if (kIsWeb && state.widget.selectionEnabled && state._value.composing.isValid) { + return false; + } + + return super.isActionEnabled; + } } class _SelectAllAction extends ContextAction { diff --git a/packages/flutter/lib/src/widgets/expansible.dart b/packages/flutter/lib/src/widgets/expansible.dart index 423a9faf62ff4..7b367e72f8f08 100644 --- a/packages/flutter/lib/src/widgets/expansible.dart +++ b/packages/flutter/lib/src/widgets/expansible.dart @@ -55,11 +55,11 @@ typedef ExpansibleBuilder = /// state. /// /// The controller's [expand] and [collapse] methods cause the -/// the [Expansible] to rebuild, so they may not be called from +/// [Expansible] to rebuild, so they may not be called from /// a build method. /// /// Remember to [dispose] of the [ExpansibleController] when it is no longer -/// needed. This will ensure we discard any resources used by the object. +/// needed. This will ensure all resources used by the object are discarded. class ExpansibleController extends ChangeNotifier { /// Creates a controller to be used with [Expansible.controller]. ExpansibleController(); diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 64dbe58bf8dcd..4463589240e30 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1570,10 +1570,41 @@ class ReadingOrderTraversalPolicy extends FocusTraversalPolicy /// {@macro flutter.widgets.FocusTraversalPolicy.requestFocusCallback} ReadingOrderTraversalPolicy({super.requestFocusCallback}); + /// Sorts the input focus nodes into reading order. + static Iterable sort(Iterable nodes) { + if (nodes.length <= 1) { + return nodes; + } + + final List<_ReadingOrderSortData> data = <_ReadingOrderSortData>[ + for (final FocusNode node in nodes) _ReadingOrderSortData(node), + ]; + + final List sortedList = []; + final List<_ReadingOrderSortData> unplaced = data; + + // Pick the initial widget as the one that is at the beginning of the band + // of the topmost, or the topmost, if there are no others in its band. + _ReadingOrderSortData current = _pickNext(unplaced); + sortedList.add(current.node); + unplaced.remove(current); + + // Go through each node, picking the next one after eliminating the previous + // one, since removing the previously picked node will expose a new band in + // which to choose candidates. + while (unplaced.isNotEmpty) { + final _ReadingOrderSortData next = _pickNext(unplaced); + current = next; + sortedList.add(current.node); + unplaced.remove(current); + } + return sortedList; + } + // Collects the given candidates into groups by directionality. The candidates // have already been sorted as if they all had the directionality of the // nearest Directionality ancestor. - List<_ReadingOrderDirectionalGroupData> _collectDirectionalityGroups( + static List<_ReadingOrderDirectionalGroupData> _collectDirectionalityGroups( Iterable<_ReadingOrderSortData> candidates, ) { TextDirection? currentDirection = candidates.first.directionality; @@ -1602,7 +1633,7 @@ class ReadingOrderTraversalPolicy extends FocusTraversalPolicy return result; } - _ReadingOrderSortData _pickNext(List<_ReadingOrderSortData> candidates) { + static _ReadingOrderSortData _pickNext(List<_ReadingOrderSortData> candidates) { // Find the topmost node by sorting on the top of the rectangles. mergeSort<_ReadingOrderSortData>( candidates, @@ -1674,35 +1705,8 @@ class ReadingOrderTraversalPolicy extends FocusTraversalPolicy // Sorts the list of nodes based on their geometry into the desired reading // order based on the directionality of the context for each node. @override - Iterable sortDescendants(Iterable descendants, FocusNode currentNode) { - if (descendants.length <= 1) { - return descendants; - } - - final List<_ReadingOrderSortData> data = <_ReadingOrderSortData>[ - for (final FocusNode node in descendants) _ReadingOrderSortData(node), - ]; - - final List sortedList = []; - final List<_ReadingOrderSortData> unplaced = data; - - // Pick the initial widget as the one that is at the beginning of the band - // of the topmost, or the topmost, if there are no others in its band. - _ReadingOrderSortData current = _pickNext(unplaced); - sortedList.add(current.node); - unplaced.remove(current); - - // Go through each node, picking the next one after eliminating the previous - // one, since removing the previously picked node will expose a new band in - // which to choose candidates. - while (unplaced.isNotEmpty) { - final _ReadingOrderSortData next = _pickNext(unplaced); - current = next; - sortedList.add(current.node); - unplaced.remove(current); - } - return sortedList; - } + Iterable sortDescendants(Iterable descendants, FocusNode currentNode) => + sort(descendants); } /// Base class for all sort orders for [OrderedTraversalPolicy] traversal. diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index a12befa5e19be..667d62dc050b2 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -677,12 +677,11 @@ class _HeroFlight { final HeroFlightDirection type = initialManifest.type; switch (type) { case HeroFlightDirection.pop: - return initial.value == 1.0 && initialManifest.isUserGestureTransition + return initialManifest.isUserGestureTransition // During user gesture transitions, the animation controller isn't - // driving the reverse transition, but should still be in a previously - // completed stage with the initial value at 1.0. - ? initial.status == AnimationStatus.completed - : initial.status == AnimationStatus.reverse; + // driving the reverse transition, so the status is not important. + || + initial.status == AnimationStatus.reverse; case HeroFlightDirection.push: return initial.value == 0.0 && initial.status == AnimationStatus.forward; } @@ -923,8 +922,15 @@ class HeroController extends NavigatorObserver { // For pop transitions driven by a user gesture: if the "to" page has // maintainState = true, then the hero's final dimensions can be measured - // immediately because their page's layout is still valid. - if (isUserGestureTransition && flightType == HeroFlightDirection.pop && toRoute.maintainState) { + // immediately because their page's layout is still valid. Unless due to directly + // adding routes to the pages stack causing the route to never get laid out. + final RenderBox? fromRouteRenderBox = toRoute.subtreeContext?.findRenderObject() as RenderBox?; + final bool hasValidSize = + (fromRouteRenderBox?.hasSize ?? false) && fromRouteRenderBox!.size.isFinite; + if (isUserGestureTransition && + flightType == HeroFlightDirection.pop && + toRoute.maintainState && + hasValidSize) { _startHeroTransition(fromRoute, toRoute, flightType, isUserGestureTransition); } else { // Otherwise, delay measuring until the end of the next frame to allow @@ -934,7 +940,6 @@ class HeroController extends NavigatorObserver { // frame completes, we'll know where the heroes in the `to` route are // going to end up, and the `to` route will go back onstage. toRoute.offstage = toRoute.animation!.value == 0.0; - WidgetsBinding.instance.addPostFrameCallback((Duration value) { if (fromRoute.navigator == null || toRoute.navigator == null) { return; diff --git a/packages/flutter/lib/src/widgets/icon.dart b/packages/flutter/lib/src/widgets/icon.dart index d2958675d6e74..9faa5f0c3ac19 100644 --- a/packages/flutter/lib/src/widgets/icon.dart +++ b/packages/flutter/lib/src/widgets/icon.dart @@ -334,7 +334,7 @@ class Icon extends StatelessWidget { switch (textDirection) { case TextDirection.rtl: iconWidget = Transform( - transform: Matrix4.identity()..scale(-1.0, 1.0, 1.0), + transform: Matrix4.identity()..scaleByDouble(-1.0, 1.0, 1.0, 1), alignment: Alignment.center, transformHitTests: false, child: iconWidget, diff --git a/packages/flutter/lib/src/widgets/interactive_viewer.dart b/packages/flutter/lib/src/widgets/interactive_viewer.dart index 2a03d4ae1ff69..216124c9abb88 100644 --- a/packages/flutter/lib/src/widgets/interactive_viewer.dart +++ b/packages/flutter/lib/src/widgets/interactive_viewer.dart @@ -12,7 +12,8 @@ import 'dart:math' as math; import 'package:flutter/foundation.dart' show clampDouble; import 'package:flutter/gestures.dart'; import 'package:flutter/physics.dart'; -import 'package:vector_math/vector_math_64.dart' show Matrix4, Quad, Vector3; +import 'package:flutter/rendering.dart'; +import 'package:vector_math/vector_math_64.dart' show Quad, Vector3; import 'basic.dart'; import 'framework.dart'; @@ -565,7 +566,7 @@ class _InteractiveViewerState extends State with TickerProvid } final Matrix4 nextMatrix = - matrix.clone()..translate(alignedTranslation.dx, alignedTranslation.dy); + matrix.clone()..translateByDouble(alignedTranslation.dx, alignedTranslation.dy, 0, 1); // Transform the viewport to determine where its four corners will be after // the child has been transformed. @@ -658,7 +659,7 @@ class _InteractiveViewerState extends State with TickerProvid ); final double clampedTotalScale = clampDouble(totalScale, widget.minScale, widget.maxScale); final double clampedScale = clampedTotalScale / currentScale; - return matrix.clone()..scale(clampedScale); + return matrix.clone()..scaleByDouble(clampedScale, clampedScale, clampedScale, 1); } // Return a new matrix representing the given matrix after applying the given @@ -669,9 +670,9 @@ class _InteractiveViewerState extends State with TickerProvid } final Offset focalPointScene = _transformer.toScene(focalPoint); return matrix.clone() - ..translate(focalPointScene.dx, focalPointScene.dy) + ..translateByDouble(focalPointScene.dx, focalPointScene.dy, 0, 1) ..rotateZ(-rotation) - ..translate(-focalPointScene.dx, -focalPointScene.dy); + ..translateByDouble(-focalPointScene.dx, -focalPointScene.dy, 0, 1); } // Returns true iff the given _GestureType is enabled. @@ -1236,9 +1237,9 @@ Quad _transformViewport(Matrix4 matrix, Rect viewport) { Quad _getAxisAlignedBoundingBoxWithRotation(Rect rect, double rotation) { final Matrix4 rotationMatrix = Matrix4.identity() - ..translate(rect.size.width / 2, rect.size.height / 2) + ..translateByDouble(rect.size.width / 2, rect.size.height / 2, 0, 1) ..rotateZ(rotation) - ..translate(-rect.size.width / 2, -rect.size.height / 2); + ..translateByDouble(-rect.size.width / 2, -rect.size.height / 2, 0, 1); final Quad boundariesRotated = Quad.points( rotationMatrix.transform3(Vector3(rect.left, rect.top, 0.0)), rotationMatrix.transform3(Vector3(rect.right, rect.top, 0.0)), diff --git a/packages/flutter/lib/src/widgets/localizations.dart b/packages/flutter/lib/src/widgets/localizations.dart index 4da5eb01eb0b6..03779659df0ad 100644 --- a/packages/flutter/lib/src/widgets/localizations.dart +++ b/packages/flutter/lib/src/widgets/localizations.dart @@ -12,7 +12,9 @@ library; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; +import 'app.dart'; import 'basic.dart'; +import 'binding.dart'; import 'debug.dart'; import 'framework.dart'; @@ -705,3 +707,214 @@ class _LocalizationsState extends State { ); } } + +/// A helper class used to manage localization resolution. +/// +/// See also: +/// * [WidgetsApp], which utilizes [LocalizationsResolver] to handle locales. +class LocalizationsResolver extends ChangeNotifier with WidgetsBindingObserver { + /// Creates a [LocalizationsResolver] that determines the best-fit locale from the set of + /// [supportedLocales]. + /// + /// If provided, locale resolution will attempt to use [locale] as the current locale rather + /// than the system locale. + /// + /// Locale resolution behavior can be overridden by providing [localeListResolutionCallback] + /// or [localeResolutionCallback]. + /// + /// The delegates set via [localizationsDelegates] collectively define all of the localized + /// resources for a [Localizations] widget. + /// + /// See also: + /// + /// * [LocalizationsResolver.localeListResolutionCallback] and + /// [LocalizationsResolver.localeResolutionCallback] for more details on locale resolution + /// behavior. + /// * [LocalizationsDelegate] for more details about providing localized resources to a + /// [Localizations] widget. + LocalizationsResolver({ + required Iterable supportedLocales, + Locale? locale, + LocaleListResolutionCallback? localeListResolutionCallback, + LocaleResolutionCallback? localeResolutionCallback, + Iterable>? localizationsDelegates, + }) : _locale = locale, + _localeListResolutionCallback = localeListResolutionCallback, + _localeResolutionCallback = localeResolutionCallback, + _localizationsDelegates = localizationsDelegates, + _supportedLocales = supportedLocales { + _resolvedLocale = _resolveLocales( + WidgetsBinding.instance.platformDispatcher.locales, + supportedLocales, + ); + WidgetsBinding.instance.addObserver(this); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + /// Replace one or more of the properties used for localization resolution and re-resolve the + /// locale. + void update({ + required Locale? locale, + required LocaleListResolutionCallback? localeListResolutionCallback, + required LocaleResolutionCallback? localeResolutionCallback, + required Iterable>? localizationsDelegates, + required Iterable supportedLocales, + }) { + _locale = locale; + _localeListResolutionCallback = localeListResolutionCallback; + _localeResolutionCallback = localeResolutionCallback; + _localizationsDelegates = localizationsDelegates; + _supportedLocales = supportedLocales; + } + + /// The currently resolved [Locale] based on the current platform locale and + /// the provided set of [supportedLocales]. + Locale get locale { + final Locale appLocale = + _locale != null ? _resolveLocales([_locale!], supportedLocales) : _resolvedLocale!; + assert(_debugCheckLocalizations(appLocale)); + return appLocale; + } + + /// {@macro flutter.widgets.widgetsApp.localizationsDelegates} + Iterable> get localizationsDelegates { + // Combine the Localizations for Widgets with the ones contributed + // by the localizationsDelegates parameter, if any. Only the first delegate + // of a particular LocalizationsDelegate.type is loaded so the + // localizationsDelegate parameter can be used to override + // WidgetsLocalizations.delegate. + return >[ + if (_localizationsDelegates != null) ..._localizationsDelegates!, + DefaultWidgetsLocalizations.delegate, + ]; + } + + Iterable>? _localizationsDelegates; + + /// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback} + /// + /// See also: + /// + /// * [basicLocaleListResolution], the default locale resolution algorithm. + LocaleListResolutionCallback? get localeListResolutionCallback => _localeListResolutionCallback; + LocaleListResolutionCallback? _localeListResolutionCallback; + + /// {@macro flutter.widgets.LocaleResolutionCallback} + LocaleResolutionCallback? get localeResolutionCallback => _localeResolutionCallback; + LocaleResolutionCallback? _localeResolutionCallback; + + /// {@macro flutter.widgets.widgetsApp.supportedLocales} + /// + /// See also: + /// + /// * [localeResolutionCallback], an app callback that resolves the app's locale + /// when the device's locale changes. + /// * [localizationsDelegates], which collectively define all of the localized + /// resources used by this app. + /// * [basicLocaleListResolution], the default locale resolution algorithm. + Iterable get supportedLocales => _supportedLocales; + Iterable _supportedLocales; + + Locale? _locale; + + /// This is the resolved locale, and is one of the supportedLocales. + Locale? _resolvedLocale; + + @override + void didChangeLocales(List? locales) { + final Locale newLocale = _resolveLocales(locales, supportedLocales); + if (newLocale != _resolvedLocale) { + _resolvedLocale = newLocale; + notifyListeners(); + } + } + + Locale _resolveLocales(List? preferredLocales, Iterable supportedLocales) { + // Attempt to use localeListResolutionCallback. + if (localeListResolutionCallback != null) { + final Locale? locale = localeListResolutionCallback!(preferredLocales, supportedLocales); + if (locale != null) { + return locale; + } + } + // localeListResolutionCallback failed, falling back to localeResolutionCallback. + if (localeResolutionCallback != null) { + final Locale? locale = localeResolutionCallback!( + preferredLocales != null && preferredLocales.isNotEmpty ? preferredLocales.first : null, + supportedLocales, + ); + if (locale != null) { + return locale; + } + } + // Both callbacks failed, falling back to default algorithm. + return basicLocaleListResolution(preferredLocales, supportedLocales); + } + + @override + String toString() => '$LocalizationsResolver'; + + bool _debugCheckLocalizations(Locale locale) { + assert(() { + final Set unsupportedTypes = + localizationsDelegates + .map((LocalizationsDelegate delegate) => delegate.type) + .toSet(); + for (final LocalizationsDelegate delegate in localizationsDelegates) { + if (!unsupportedTypes.contains(delegate.type)) { + continue; + } + if (delegate.isSupported(locale)) { + unsupportedTypes.remove(delegate.type); + } + } + if (unsupportedTypes.isEmpty) { + return true; + } + + FlutterError.reportError( + FlutterErrorDetails( + exception: + "Warning: This application's locale, $locale, is not supported by all of its localization delegates.", + library: 'widgets', + informationCollector: + () => [ + for (final Type unsupportedType in unsupportedTypes) + ErrorDescription( + '• A $unsupportedType delegate that supports the $locale locale was not found.', + ), + ErrorSpacer(), + if (unsupportedTypes.length == 1 && + unsupportedTypes.single.toString() == 'CupertinoLocalizations') + // We previously explicitly avoided checking for this class so it's not uncommon for applications + // to have omitted importing the required delegate. + ...[ + ErrorHint( + 'If the application is built using GlobalMaterialLocalizations.delegate, consider using ' + 'GlobalMaterialLocalizations.delegates (plural) instead, as that will automatically declare ' + 'the appropriate Cupertino localizations.', + ), + ErrorSpacer(), + ], + ErrorHint( + 'The declared supported locales for this app are: ${supportedLocales.join(", ")}', + ), + ErrorSpacer(), + ErrorDescription( + 'See https://flutter.dev/to/internationalization/ for more ' + "information about configuring an app's locale, supportedLocales, " + 'and localizationsDelegates parameters.', + ), + ], + ), + ); + return true; + }()); + return true; + } +} diff --git a/packages/flutter/lib/src/widgets/magnifier.dart b/packages/flutter/lib/src/widgets/magnifier.dart index cacf3d235bd21..faa809d233d01 100644 --- a/packages/flutter/lib/src/widgets/magnifier.dart +++ b/packages/flutter/lib/src/widgets/magnifier.dart @@ -631,11 +631,13 @@ class _RenderMagnification extends RenderProxyBox { final Offset thisCenter = Alignment.center.alongSize(size) + offset; final Matrix4 matrix = Matrix4.identity() - ..translate( + ..translateByDouble( magnificationScale * ((focalPointOffset.dx * -1) - thisCenter.dx) + thisCenter.dx, magnificationScale * ((focalPointOffset.dy * -1) - thisCenter.dy) + thisCenter.dy, + 0, + 1, ) - ..scale(magnificationScale); + ..scaleByDouble(magnificationScale, magnificationScale, magnificationScale, 1); final ImageFilter filter = ImageFilter.matrix( matrix.storage, filterQuality: FilterQuality.high, diff --git a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart index f6d3eeb9c5e71..2333565aba733 100644 --- a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart +++ b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart @@ -10,10 +10,10 @@ import 'pop_scope.dart'; /// Enables the handling of system back gestures. /// /// Typically wraps a nested [Navigator] widget and allows it to handle system -/// back gestures in the [onPop] callback. +/// back gestures in the [onPopWithResult] callback. /// /// The type parameter `` indicates the type of the [Route]'s return value, -/// which is passed to [onPopWithResult. +/// which is passed to [onPopWithResult]. /// /// {@tool dartpad} /// This sample demonstrates how to use this widget to properly handle system @@ -53,8 +53,8 @@ class NavigatorPopHandler extends StatefulWidget { /// The widget to place below this in the widget tree. /// - /// Typically this is a [Navigator] that will handle the pop when [onPop] is - /// called. + /// Typically this is a [Navigator] that will handle the pop when + /// [onPopWithResult] is called. final Widget child; /// Whether this widget's ability to handle system back gestures is enabled or @@ -87,7 +87,7 @@ class NavigatorPopHandler extends StatefulWidget { /// /// For example, a pop is handleable when a [Navigator] in [child] has /// multiple routes on its stack. It's not handleable when it has only a - /// single route, and so [onPop] will not be called. + /// single route, and so [onPopWithResult] will not be called. /// /// Typically this is used to pop the [Navigator] in [child]. See the sample /// code on [NavigatorPopHandler] for a full example of this. diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index bd01fd9814ce1..10c0f61113131 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -2547,7 +2547,7 @@ final class _RenderDeferredLayoutBox extends RenderProxyBox void applyPaintTransform(RenderBox child, Matrix4 transform) { final BoxParentData childParentData = child.parentData! as BoxParentData; final Offset offset = childParentData.offset; - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } } @@ -2663,7 +2663,7 @@ class _RenderLayoutBuilder extends RenderProxyBox void applyPaintTransform(RenderBox child, Matrix4 transform) { final BoxParentData childParentData = child.parentData! as BoxParentData; final Offset offset = childParentData.offset; - transform.translate(offset.dx, offset.dy); + transform.translateByDouble(offset.dx, offset.dy, 0, 1); } @protected diff --git a/packages/flutter/lib/src/widgets/radio_group.dart b/packages/flutter/lib/src/widgets/radio_group.dart new file mode 100644 index 0000000000000..5086cb12aeba4 --- /dev/null +++ b/packages/flutter/lib/src/widgets/radio_group.dart @@ -0,0 +1,327 @@ +// Copyright 2014 The Flutter Authors. 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' show SemanticsRole; + +import 'package:collection/collection.dart'; +import 'package:flutter/services.dart'; + +import 'actions.dart'; +import 'basic.dart'; +import 'focus_manager.dart'; +import 'focus_traversal.dart'; +import 'framework.dart'; +import 'shortcuts.dart'; + +/// A group for radios. +/// +/// This widget treats all radios, such as [RawRadio], [Radio], [CupertinoRadio] +/// in the sub tree with the same type T as a group. Radios with different types +/// are not included in the group. +/// +/// This widget handles the group value for the radios in the subtree with the +/// same value type. +/// +/// Using this widget also provides keyboard navigation and semantics for the +/// radio buttons that matches [APG](https://www.w3.org/WAI/ARIA/apg/patterns/radio/). +/// +/// The keyboard behaviors are: +/// * Tab and Shift+Tab: moves focus into and out of radio group. When focus +/// moves into a radio group and a radio button is select, focus is set on +/// selected button. Otherwise, it focus the first radio button in reading +/// order. +/// * Space: toggle the selection on the focused radio button. +/// * Right and down arrow key: move selection to next radio button in the group +/// in reading order. +/// * Left and up arrow key: move selection to previous radio button in the +/// group in reading order. +/// +/// Arrow keys will wrap around if it reach the first or last radio in the +/// group. +/// +/// {@tool dartpad} +/// Here is an example of RadioGroup widget. +/// +/// Try using tab, arrow keys, and space to see how the widget responds. +/// +/// ** See code in examples/api/lib/widgets/radio_group/radio_group.0.dart ** +/// {@end-tool} +class RadioGroup extends StatefulWidget { + /// Creates a radio group. + /// + /// The `groupValue` set the selection on a subtree radio with the same + /// [RawRadio.value]. + /// + /// The `onChanged` is called when the selection has changed in the subtree + /// radios. + const RadioGroup({super.key, this.groupValue, required this.onChanged, required this.child}); + + /// The selected value under this radio group. + /// + /// [RawRadio] under this radio group where its [RawRadio.value] equals to this + /// value will be selected. + final T? groupValue; + + /// Called when selection has changed. + /// + /// The value can be null when unselect the [RawRadio] with + /// [RawRadio.toggleable] set to true. + final ValueChanged onChanged; + + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget child; + + /// Gets the [RadioGroupRegistry] from the above the context. + /// + /// This registers a dependencies on the context that it causes rebuild + /// if [RadioGroupRegistry] has changed or its + /// [RadioGroupRegistry.groupValue] has changed. + static RadioGroupRegistry? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType<_RadioGroupStateScope>()?.state; + } + + @override + State createState() => _RadioGroupState(); +} + +class _RadioGroupState extends State> implements RadioGroupRegistry { + late final Map _radioGroupShortcuts = { + const SingleActivator(LogicalKeyboardKey.arrowLeft): VoidCallbackIntent(_selectPreviousRadio), + const SingleActivator(LogicalKeyboardKey.arrowRight): VoidCallbackIntent(_selectNextRadio), + const SingleActivator(LogicalKeyboardKey.arrowDown): VoidCallbackIntent(_selectNextRadio), + const SingleActivator(LogicalKeyboardKey.arrowUp): VoidCallbackIntent(_selectPreviousRadio), + const SingleActivator(LogicalKeyboardKey.space): VoidCallbackIntent(_toggleFocusedRadio), + }; + + final Set> _radios = >{}; + + bool _debugCheckOnlySingleSelection() { + return _radios.where((RadioClient radio) => radio.radioValue == groupValue).length < 2; + } + + @override + T? get groupValue => widget.groupValue; + + @override + void registerClient(RadioClient radio) { + _radios.add(radio); + assert( + _debugCheckOnlySingleSelection(), + "RadioGroupPolicy can't be used for a radio group that allows multiple selection", + ); + } + + @override + void unregisterClient(RadioClient radio) => _radios.remove(radio); + + void _toggleFocusedRadio() { + final RadioClient? radio = _radios.firstWhereOrNull( + (RadioClient radio) => radio.focusNode.hasFocus, + ); + if (radio == null) { + return; + } + if (radio.radioValue != widget.groupValue) { + onChanged(radio.radioValue); + return; + } + + if (radio.tristate) { + onChanged(null); + } + } + + @override + ValueChanged get onChanged => widget.onChanged; + + void _selectNextRadio() => _selectRadioInDirection(true); + + void _selectPreviousRadio() => _selectRadioInDirection(false); + + void _selectRadioInDirection(bool forward) { + if (_radios.length < 2) { + return; + } + final FocusNode? currentFocus = + _radios.firstWhereOrNull((RadioClient radio) => radio.focusNode.hasFocus)?.focusNode; + if (currentFocus == null) { + // The focused node is either a non interactive radio or other controls. + return; + } + final List sorted = + ReadingOrderTraversalPolicy.sort( + _radios.map((RadioClient radio) => radio.focusNode), + ).toList(); + final Iterable nodesInEffectiveOrder = forward ? sorted : sorted.reversed; + + final Iterator iterator = nodesInEffectiveOrder.iterator; + FocusNode? nextFocus; + while (iterator.moveNext()) { + if (iterator.current == currentFocus) { + if (iterator.moveNext()) { + nextFocus = iterator.current; + } + break; + } + } + // Current focus is at the end, the next focus should wrap around. + nextFocus ??= nodesInEffectiveOrder.first; + final RadioClient radioToSelect = _radios.firstWhere( + (RadioClient radio) => radio.focusNode == nextFocus, + ); + onChanged(radioToSelect.radioValue); + nextFocus.requestFocus(); + } + + @override + Widget build(BuildContext context) { + return Semantics( + role: SemanticsRole.radioGroup, + child: Shortcuts( + shortcuts: _radioGroupShortcuts, + child: FocusTraversalGroup( + policy: _SkipUnselectedRadioPolicy(_radios, widget.groupValue), + child: _RadioGroupStateScope( + state: this, + groupValue: widget.groupValue, + child: widget.child, + ), + ), + ), + ); + } +} + +class _RadioGroupStateScope extends InheritedWidget { + const _RadioGroupStateScope({required this.state, required this.groupValue, required super.child}) + : super(); + final _RadioGroupState state; + // Need to include group value to notify listener when group value changes. + final T? groupValue; + + @override + bool updateShouldNotify(covariant _RadioGroupStateScope oldWidget) { + return state != oldWidget.state || groupValue != oldWidget.groupValue; + } +} + +/// An abstract interface for registering a group of radios. +/// +/// Use [registerClient] or [unregisterClient] to handle registrations of radios. +/// +/// The registry manages the group value for the radios. The radio needs to call +/// [onChanged] to notify the group value needs to be changed. +abstract class RadioGroupRegistry { + /// The group value for the group. + T? get groupValue; + + /// Registers a radio client. + /// + /// The subclass provides additional features, such as keyboard navigation + /// for the registered clients. + void registerClient(RadioClient radio); + + /// Unregisters a radio client. + void unregisterClient(RadioClient radio); + + /// Notifies the registry that the a radio is selected or unselected. + ValueChanged get onChanged; +} + +/// A client for a [RadioGroupRegistry]. +/// +/// This is typically mixed with a [State]. +/// +/// To register to a [RadioGroupRegistry], assign the registry to [registry]. +/// +/// To unregister from previous [RadioGroupRegistry], either assign a different +/// value to [registry] or set it to null. +mixin RadioClient { + /// Whether this radio support toggles. + /// + /// Used by registry to provide additional feature such as keyboard support. + bool get tristate; + + /// This value this radio represents. + /// + /// Used by registry to provide additional feature such as keyboard support. + T get radioValue; + + /// Focus node for this radio. + /// + /// Used by registry to provide additional feature such as keyboard support. + FocusNode get focusNode; + + /// The [RadioGroupRegistry] this client register to. + /// + /// Setting this property automatically register to the new value and + /// unregister the old value. + /// + /// This should set to null when dispose. + RadioGroupRegistry? get registry => _registry; + RadioGroupRegistry? _registry; + set registry(RadioGroupRegistry? newRegistry) { + if (_registry != newRegistry) { + _registry?.unregisterClient(this); + } + _registry = newRegistry; + _registry?.registerClient(this); + } +} + +/// A traversal policy that is the same as [ReadingOrderTraversalPolicy] except +/// it skips nodes of unselected radio button if there is one selected radio +/// button. +/// +/// If none of the radio is selected, this defaults to +/// [ReadingOrderTraversalPolicy] for all nodes. +/// +/// This policy is to ensure when tabbing into a radio group, it will only focus +/// the current selected radio button and prevent focus from reaching unselected +/// ones. +class _SkipUnselectedRadioPolicy extends ReadingOrderTraversalPolicy { + _SkipUnselectedRadioPolicy(this.radios, this.groupValue); + final Set> radios; + final T? groupValue; + + bool _radioSelected(RadioClient radio) => radio.radioValue == groupValue; + + @override + Iterable sortDescendants(Iterable descendants, FocusNode currentNode) { + final Iterable nodesInReadOrder = super.sortDescendants(descendants, currentNode); + RadioClient? selected = radios.firstWhereOrNull(_radioSelected); + + if (selected == null) { + // None of the radio are selected. Select the first radio in read order. + final Map> radioFocusNodes = >{}; + for (final RadioClient radio in radios) { + radioFocusNodes[radio.focusNode] = radio; + } + + for (final FocusNode node in nodesInReadOrder) { + selected = radioFocusNodes[node]; + if (selected != null) { + break; + } + } + } + + if (selected == null) { + // None of the radio is selected or focusable, defaults to reading order + return nodesInReadOrder; + } + + // Nodes that are not selected AND not currently focused, since we can't + // remove the focused node from the sorted result. + final Set nodeToSkip = + radios + .where((RadioClient radio) => selected != radio && radio.focusNode != currentNode) + .map((RadioClient radio) => radio.focusNode) + .toSet(); + final Iterable skipsNonSelected = descendants.where( + (FocusNode node) => !nodeToSkip.contains(node), + ); + return super.sortDescendants(skipsNonSelected, currentNode); + } +} diff --git a/packages/flutter/lib/src/widgets/raw_menu_anchor.dart b/packages/flutter/lib/src/widgets/raw_menu_anchor.dart index 4212357151a3a..16e959bc28176 100644 --- a/packages/flutter/lib/src/widgets/raw_menu_anchor.dart +++ b/packages/flutter/lib/src/widgets/raw_menu_anchor.dart @@ -156,6 +156,11 @@ class _MenuControllerScope extends InheritedWidget { /// Users are responsible for managing the positioning, semantics, and focus of /// the menu. /// +/// To programmatically control a [RawMenuAnchor], like opening or closing it, or checking its state, +/// you can get its associated [MenuController]. Use `MenuController.maybeOf(BuildContext context)` +/// to retrieve the controller for the closest [RawMenuAnchor] ancestor of a given `BuildContext`. +/// More detailed usage of [MenuController] is available in its class documentation. +/// /// {@tool dartpad} /// /// This example uses a [RawMenuAnchor] to build a basic select menu with diff --git a/packages/flutter/lib/src/widgets/raw_radio.dart b/packages/flutter/lib/src/widgets/raw_radio.dart index 27f1a27601ec4..1378b7fb17d14 100644 --- a/packages/flutter/lib/src/widgets/raw_radio.dart +++ b/packages/flutter/lib/src/widgets/raw_radio.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'basic.dart'; import 'focus_manager.dart'; import 'framework.dart'; +import 'radio_group.dart'; import 'ticker_provider.dart'; import 'toggleable.dart'; import 'widget_state.dart'; @@ -30,11 +31,9 @@ typedef RadioBuilder = Widget Function(BuildContext context, ToggleableStateMixi /// group cease to be selected. The values are of type `T`, the type parameter /// of the radio class. Enums are commonly used for this purpose. /// -/// The radio button itself does not maintain any state. Instead, selecting the -/// radio invokes the [onChanged] callback, passing [value] as a parameter. If -/// [groupValue] and [value] match, this radio will be selected. Most widgets -/// will respond to [onChanged] by calling [State.setState] to update the -/// radio button's [groupValue]. +/// {@macro flutter.widget.RawRadio.groupValue} +/// +/// If [enabled] is false, the radio will not be interactive. /// /// See also: /// @@ -44,57 +43,24 @@ typedef RadioBuilder = Widget Function(BuildContext context, ToggleableStateMixi class RawRadio extends StatefulWidget { /// Creates a radio button. /// - /// The radio button itself does not maintain any state. Instead, when the - /// radio button is selected, the widget calls the [onChanged] callback. Most - /// widgets that use a radio button will listen for the [onChanged] callback - /// and rebuild the radio button with a new [groupValue] to update the visual - /// appearance of the radio button. + /// If [enabled] is true, the [groupRegistry] must not be null. const RawRadio({ super.key, required this.value, - required this.groupValue, - required this.onChanged, required this.mouseCursor, required this.toggleable, required this.focusNode, required this.autofocus, + required this.groupRegistry, + required this.enabled, required this.builder, - }); + }) : assert(!enabled || groupRegistry != null, 'an enabled raw radio must have a registry'); /// {@template flutter.widget.RawRadio.value} /// The value represented by this radio button. /// {@endtemplate} final T value; - /// {@template flutter.widget.RawRadio.groupValue} - /// The currently selected value for a group of radio buttons. - /// - /// This radio button is considered selected if its [value] matches the - /// [groupValue]. - /// {@endtemplate} - final T? groupValue; - - /// {@template flutter.widget.RawRadio.onChanged} - /// Called when the user selects this radio button. - /// - /// The radio button passes [value] as a parameter to this callback. The radio - /// button does not actually change state until the parent widget rebuilds the - /// radio button with the new [groupValue]. - /// - /// If null, the radio button will be displayed as disabled. - /// - /// The provided callback will not be invoked if this radio button is already - /// selected and [toggleable] is not set to true. - /// - /// If the [toggleable] is set to true, tapping a already selected radio will - /// invoke this callback with `null` as value. - /// - /// The callback provided to [onChanged] should update the state of the parent - /// [StatefulWidget] using the [State.setState] method, so that the parent - /// gets rebuilt. - /// {@endtemplate} - final ValueChanged? onChanged; - /// {@template flutter.widget.RawRadio.mouseCursor} /// The cursor for a mouse pointer when it enters or is hovering over the /// widget. @@ -113,24 +79,24 @@ class RawRadio extends StatefulWidget { /// Set to true if this radio button is allowed to be returned to an /// indeterminate state by selecting it again when selected. /// - /// To indicate returning to an indeterminate state, [onChanged] will be - /// called with null. + /// To indicate returning to an indeterminate state, [RadioGroup.onChanged] + /// of the [RadioGroup] above the widget tree will be called with null. /// - /// If true, [onChanged] is called with [value] when selected while - /// [groupValue] != [value], and with null when selected again while - /// [groupValue] == [value]. + /// If true, [RadioGroup.onChanged] is called with [value] when selected while + /// [RadioGroup.groupValue] != [value], and with null when selected again while + /// [RadioGroup.groupValue] == [value]. /// - /// If false, [onChanged] will be called with [value] when it is selected - /// while [groupValue] != [value], and only by selecting another radio button - /// in the group (i.e. changing the value of [groupValue]) can this radio - /// button be unselected. + /// If false, [RadioGroup.onChanged] will be called with [value] when it is + /// selected while [RadioGroup.groupValue] != [value], and only by selecting + /// another radio button in the group (i.e. changing the value of + /// [RadioGroup.groupValue]) can this radio button be unselected. /// /// The default is false. /// {@endtemplate} final bool toggleable; /// {@macro flutter.widgets.Focus.focusNode} - final FocusNode? focusNode; + final FocusNode focusNode; /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; @@ -142,40 +108,86 @@ class RawRadio extends StatefulWidget { /// {@macro flutter.widgets.ToggleableStateMixin.buildToggleableWithChild} final RadioBuilder builder; - bool get _selected => value == groupValue; + /// Whether this widget is enabled. + final bool enabled; + + /// {@template flutter.widget.RawRadio.groupRegistry} + /// The registry this radio registers to. + /// {@endtemplate} + /// + /// {@template flutter.widget.RawRadio.groupValue} + /// The radio relies on [groupRegistry] to maintains the state for selection. + /// If use in conjunction with a [RadioGroup] widget, use [RadioGroup.maybeOf] + /// to get the group registry from the context. + /// {@endtemplate} + final RadioGroupRegistry? groupRegistry; @override State> createState() => _RawRadioState(); } class _RawRadioState extends State> - with TickerProviderStateMixin, ToggleableStateMixin { + with TickerProviderStateMixin, ToggleableStateMixin, RadioClient { + @override + FocusNode get focusNode => widget.focusNode; + + @override + T get radioValue => widget.value; + + @override + void initState() { + // This has to be before the init state because the [ToggleableStateMixin] + // expect the [value] is up-to-date when init its state. + registry = widget.groupRegistry; + super.initState(); + } + + /// Handle selection status changed. + /// + /// if `selected` is false, nothing happens. + /// + /// if `selected` is true, select this radio. i.e. [Radio.onChanged] is called + /// with [Radio.value]. This also updates the group value in [RadioGroup] if it + /// is in use. + /// + /// if `selected` is null, unselect this radio. Same as `selected` is true + /// except group value is set to null. void _handleChanged(bool? selected) { - if (selected == null) { - widget.onChanged!(null); + assert(registry != null); + if (!(selected ?? true)) { return; } - if (selected) { - widget.onChanged!(widget.value); + if (selected ?? false) { + registry!.onChanged(widget.value); + } else { + registry!.onChanged(null); } } @override void didUpdateWidget(RawRadio oldWidget) { super.didUpdateWidget(oldWidget); - if (widget._selected != oldWidget._selected) { - animateToValue(); - } + registry = widget.groupRegistry; + animateToValue(); // The registry's group value may have changed + } + + @override + void dispose() { + super.dispose(); + registry = null; } @override - ValueChanged? get onChanged => widget.onChanged != null ? _handleChanged : null; + ValueChanged? get onChanged => registry != null ? _handleChanged : null; @override bool get tristate => widget.toggleable; @override - bool? get value => widget._selected; + bool? get value => widget.value == registry?.groupValue; + + @override + bool get isInteractive => widget.enabled; @override Widget build(BuildContext context) { @@ -188,15 +200,15 @@ class _RawRadioState extends State> accessibilitySelected = null; case TargetPlatform.iOS: case TargetPlatform.macOS: - accessibilitySelected = widget._selected; + accessibilitySelected = value; } return Semantics( inMutuallyExclusiveGroup: true, - checked: widget._selected, + checked: value, selected: accessibilitySelected, child: buildToggleableWithChild( - focusNode: widget.focusNode, + focusNode: focusNode, autofocus: widget.autofocus, mouseCursor: widget.mouseCursor, child: widget.builder(context, this), diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index c61dd7a862a64..80c2f371366ef 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -971,6 +971,18 @@ enum _ModalRouteAspect { /// Specifies the aspect corresponding to [ModalRoute.settings]. settings, + + /// Specifies the aspect corresponding to [ModalRoute.isActive]. + isActive, + + /// Specifies the aspect corresponding to [ModalRoute.isFirst]. + isFirst, + + /// Specifies the aspect corresponding to [ModalRoute.opaque]. + opaque, + + /// Specifies the aspect corresponding to [ModalRoute.popDisposition]. + popDisposition, } class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { @@ -979,12 +991,14 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { required this.canPop, required this.impliesAppBarDismissal, required this.route, + required this.opaque, required super.child, }); final bool isCurrent; final bool canPop; final bool impliesAppBarDismissal; + final bool opaque; final Route route; @override @@ -992,7 +1006,8 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { return isCurrent != old.isCurrent || canPop != old.canPop || impliesAppBarDismissal != old.impliesAppBarDismissal || - route != old.route; + route != old.route || + opaque != old.opaque; } @override @@ -1021,6 +1036,10 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { _ModalRouteAspect.isCurrent => isCurrent != oldWidget.isCurrent, _ModalRouteAspect.canPop => canPop != oldWidget.canPop, _ModalRouteAspect.settings => route.settings != oldWidget.route.settings, + _ModalRouteAspect.isActive => route.isActive != oldWidget.route.isActive, + _ModalRouteAspect.isFirst => route.isFirst != oldWidget.route.isFirst, + _ModalRouteAspect.opaque => opaque != oldWidget.opaque, + _ModalRouteAspect.popDisposition => route.popDisposition != oldWidget.route.popDisposition, }, ); } @@ -1143,6 +1162,7 @@ class _ModalScopeState extends State<_ModalScope> { route: widget.route, isCurrent: widget.route.isCurrent, // _routeSetState is called if this updates canPop: widget.route.canPop, // _routeSetState is called if this updates + opaque: widget.route.opaque, // _routeSetState is called if this updates impliesAppBarDismissal: widget.route.impliesAppBarDismissal, child: Offstage( offstage: widget.route.offstage, // _routeSetState is called if this updates @@ -1299,11 +1319,54 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute _of(context, _ModalRouteAspect.settings)?.settings; + /// Returns [ModalRoute.isActive] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.isActive] changes. + static bool? isActiveOf(BuildContext context) => + _of(context, _ModalRouteAspect.isActive)?.isActive; + + /// Returns [ModalRoute.isFirst] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.isFirst] changes. + static bool? isFirstOf(BuildContext context) => _of(context, _ModalRouteAspect.isFirst)?.isFirst; + + /// Returns [ModalRoute.opaque] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.opaque] changes. + static bool? opaqueOf(BuildContext context) => _of(context, _ModalRouteAspect.opaque)?.opaque; + + /// Returns [ModalRoute.popDisposition] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.popDisposition] changes. + static RoutePopDisposition? popDispositionOf(BuildContext context) => + _of(context, _ModalRouteAspect.popDisposition)?.popDisposition; + /// Schedule a call to [buildTransitions]. /// /// Whenever you need to change internal state for a [ModalRoute] object, make diff --git a/packages/flutter/lib/src/widgets/scroll_delegate.dart b/packages/flutter/lib/src/widgets/scroll_delegate.dart index f3de6fd386f06..b5902065c3166 100644 --- a/packages/flutter/lib/src/widgets/scroll_delegate.dart +++ b/packages/flutter/lib/src/widgets/scroll_delegate.dart @@ -413,6 +413,60 @@ class SliverChildBuilderDelegate extends SliverChildDelegate { /// none of the children will ever try to keep themselves alive. /// /// Defaults to true. + /// + /// {@tool dartpad} + /// This sample demonstrates how to use the [AutomaticKeepAlive] widget in + /// combination with the [AutomaticKeepAliveClientMixin] to selectively preserve + /// the state of individual items in a scrollable list. + /// + /// Normally, widgets in a lazily built list like [ListView.builder] are + /// disposed of when they leave the visible area to maintain performance. This means + /// that any state inside a [StatefulWidget] would be lost unless explicitly + /// preserved. + /// + /// In this example, each list item is a [StatefulWidget] that includes a + /// counter and an increment button. To preserve the state of selected items + /// (based on their index), the [AutomaticKeepAlive] widget and + /// [AutomaticKeepAliveClientMixin] are used: + /// + /// - The `wantKeepAlive` getter in the item’s state class returns true for + /// even-indexed items, indicating that their state should be preserved. + /// - For odd-indexed items, `wantKeepAlive` returns false, so their state is + /// not preserved when scrolled out of view. + /// + /// ** See code in examples/api/lib/widgets/keep_alive/automatic_keep_alive.0.dart ** + /// {@end-tool} + /// + /// {@tool dartpad} + /// This sample demonstrates how to use the [KeepAlive] widget + /// to preserve the state of individual list items in a [ListView] when they are + /// scrolled out of view. + /// + /// By default, [ListView.builder] only keeps the widgets currently visible in + /// the viewport alive. When an item scrolls out of view, it may be disposed to + /// free up resources. This can cause the state of [StatefulWidget]s to be lost + /// if not explicitly preserved. + /// + /// In this example, each item in the list is a [StatefulWidget] that maintains + /// a counter. Tapping the "+" button increments the counter. To selectively + /// preserve the state, each item is wrapped in a [KeepAlive] widget, with the + /// keepAlive parameter set based on the item’s index: + /// + /// - For even-indexed items, `keepAlive: true`, so their state is preserved + /// even when scrolled off-screen. + /// - For odd-indexed items, `keepAlive: false`, so their state is discarded + /// when they are no longer visible. + /// + /// ** See code in examples/api/lib/widgets/keep_alive/keep_alive.0.dart ** + /// {@end-tool} + /// + /// * [AutomaticKeepAlive], which allows subtrees to request to be kept alive + /// in lazy lists. + /// * [AutomaticKeepAliveClientMixin], which is a mixin with convenience + /// methods for clients of [AutomaticKeepAlive]. Used with [State] + /// subclasses. + /// * [KeepAlive] which marks a child as needing to stay alive even when it's + /// in a lazy list that would otherwise remove it. /// {@endtemplate} final bool addAutomaticKeepAlives; diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index b3968991f215a..ca533e79c6340 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -576,7 +576,7 @@ class _RenderSingleChildViewport extends RenderBox @override void applyPaintTransform(RenderBox child, Matrix4 transform) { final Offset paintOffset = _paintOffset; - transform.translate(paintOffset.dx, paintOffset.dy); + transform.translateByDouble(paintOffset.dx, paintOffset.dy, 0, 1); } @override diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index b89cdaa03d4df..ef06fda8cd158 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -1444,26 +1444,24 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement { /// Mark a child as needing to stay alive even when it's in a lazy list that /// would otherwise remove it. /// -/// This widget is for use in a [RenderAbstractViewport]s, such as -/// [Viewport] or [TwoDimensionalViewport]. -/// -/// This widget is rarely used directly. The [SliverChildBuilderDelegate] and -/// [SliverChildListDelegate] delegates, used with [SliverList] and -/// [SliverGrid], as well as the scroll view counterparts [ListView] and -/// [GridView], have an `addAutomaticKeepAlives` feature, which is enabled by -/// default, and which causes [AutomaticKeepAlive] widgets to be inserted around -/// each child, causing [KeepAlive] widgets to be automatically added and -/// configured in response to [KeepAliveNotification]s. -/// -/// The same `addAutomaticKeepAlives` feature is supported by the +/// This widget is used in [RenderAbstractViewport]s, such as [Viewport] or +/// [TwoDimensionalViewport], to manage the lifecycle of widgets that need to +/// remain alive even when scrolled out of view. +/// +/// The [SliverChildBuilderDelegate] and [SliverChildListDelegate] delegates, +/// used with [SliverList] and [SliverGrid], as well as the scroll view +/// counterparts [ListView] and [GridView], have an `addAutomaticKeepAlives` +/// feature, which is enabled by default. This feature inserts +/// [AutomaticKeepAlive] widgets around each child, which in turn configure +/// [KeepAlive] widgets in response to [KeepAliveNotification]s. +/// +/// The same `addAutomaticKeepAlives` feature is supported by /// [TwoDimensionalChildBuilderDelegate] and [TwoDimensionalChildListDelegate]. /// -/// Therefore, to keep a widget alive, it is more common to use those -/// notifications than to directly deal with [KeepAlive] widgets. -/// -/// In practice, the simplest way to deal with these notifications is to mix -/// [AutomaticKeepAliveClientMixin] into one's [State]. See the documentation -/// for that mixin class for details. +/// Keep-alive behavior can be managed by using [KeepAlive] directly or by +/// relying on notifications. For convenience, [AutomaticKeepAliveClientMixin] +/// may be mixed into a [State] subclass. Further details are available in the +/// documentation for [AutomaticKeepAliveClientMixin]. /// /// {@tool dartpad} /// This sample demonstrates how to use the [KeepAlive] widget @@ -1488,6 +1486,13 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement { /// ** See code in examples/api/lib/widgets/keep_alive/keep_alive.0.dart ** /// {@end-tool} /// +/// See also: +/// +/// * [AutomaticKeepAlive], which allows subtrees to request to be kept alive +/// in lazy lists. +/// * [AutomaticKeepAliveClientMixin], which is a mixin with convenience +/// methods for clients of [AutomaticKeepAlive]. Used with [State] +/// subclasses. class KeepAlive extends ParentDataWidget { /// Marks a child as needing to remain alive. const KeepAlive({super.key, required this.keepAlive, required super.child}); diff --git a/packages/flutter/lib/src/widgets/system_context_menu.dart b/packages/flutter/lib/src/widgets/system_context_menu.dart index 2c97d9deecbc6..44b88996a1b05 100644 --- a/packages/flutter/lib/src/widgets/system_context_menu.dart +++ b/packages/flutter/lib/src/widgets/system_context_menu.dart @@ -5,6 +5,7 @@ /// @docImport 'package:flutter/material.dart'; library; +import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -320,7 +321,7 @@ final class IOSSystemContextMenuItemSelectAll extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataLookUp], which specifies the data to be sent /// to the platform for this same button. -final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemLookUp]. const IOSSystemContextMenuItemLookUp({this.title}); @@ -333,8 +334,9 @@ final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemLookUp(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('title', title)); } } @@ -355,7 +357,7 @@ final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataSearchWeb], which specifies the data to be /// sent to the platform for this same button. -final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemSearchWeb]. const IOSSystemContextMenuItemSearchWeb({this.title}); @@ -370,8 +372,9 @@ final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemSearchWeb(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('title', title)); } } @@ -392,7 +395,7 @@ final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataShare], which specifies the data to be sent /// to the platform for this same button. -final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemShare]. const IOSSystemContextMenuItemShare({this.title}); @@ -405,8 +408,9 @@ final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemShare(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(StringProperty('title', title)); } } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 1b9044d198db1..5fe43d3b712cf 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -55,7 +55,7 @@ typedef MoveExitWidgetSelectionButtonBuilder = BuildContext context, { required VoidCallback onPressed, required String semanticsLabel, - bool isLeftAligned, + bool usesDefaultAlignment, }); /// Signature for the builder callback used by @@ -3737,7 +3737,11 @@ class _WidgetInspectorButtonGroupState extends State<_WidgetInspectorButtonGroup String? _tooltipMessage; - bool _leftAligned = true; + /// Indicates whether the button is using the default alignment based on text direction. + /// + /// For LTR, the default alignment is on the left. + /// For RTL, the default alignment is on the right. + bool _usesDefaultAlignment = true; ValueNotifier get _selectionOnTapEnabled => WidgetsBinding.instance.debugWidgetInspectorSelectionOnTapEnabled; @@ -3749,7 +3753,11 @@ class _WidgetInspectorButtonGroupState extends State<_WidgetInspectorButtonGroup return null; } - final String buttonLabel = 'Move to the ${_leftAligned ? 'right' : 'left'}'; + final TextDirection textDirection = Directionality.of(context); + + final String buttonLabel = + 'Move to the ${_usesDefaultAlignment == (textDirection == TextDirection.ltr) ? 'right' : 'left'}'; + return _WidgetInspectorButton( button: buttonBuilder( context, @@ -3758,7 +3766,7 @@ class _WidgetInspectorButtonGroupState extends State<_WidgetInspectorButtonGroup _onTooltipHidden(); }, semanticsLabel: buttonLabel, - isLeftAligned: _leftAligned, + usesDefaultAlignment: _usesDefaultAlignment, ), onTooltipVisible: () { _changeTooltipMessage(buttonLabel); @@ -3819,24 +3827,25 @@ class _WidgetInspectorButtonGroupState extends State<_WidgetInspectorButtonGroup painter: _ExitWidgetSelectionTooltipPainter( tooltipMessage: _tooltipMessage, buttonKey: _exitWidgetSelectionButtonKey, - isLeftAligned: _leftAligned, + usesDefaultAlignment: _usesDefaultAlignment, ), ), Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.center, children: [ - if (_leftAligned) selectionModeButtons, + if (_usesDefaultAlignment) selectionModeButtons, if (_moveExitWidgetSelectionButton != null) _moveExitWidgetSelectionButton!, - if (!_leftAligned) selectionModeButtons, + if (!_usesDefaultAlignment) selectionModeButtons, ], ), ], ); - return Positioned( - left: _leftAligned ? _kExitWidgetSelectionButtonMargin : null, - right: _leftAligned ? null : _kExitWidgetSelectionButtonMargin, + return Positioned.directional( + textDirection: Directionality.of(context), + start: _usesDefaultAlignment ? _kExitWidgetSelectionButtonMargin : null, + end: _usesDefaultAlignment ? null : _kExitWidgetSelectionButtonMargin, bottom: _kExitWidgetSelectionButtonMargin, child: buttonGroup, ); @@ -3868,7 +3877,7 @@ class _WidgetInspectorButtonGroupState extends State<_WidgetInspectorButtonGroup void _changeButtonGroupAlignment() { if (mounted) { setState(() { - _leftAligned = !_leftAligned; + _usesDefaultAlignment = !_usesDefaultAlignment; }); } } @@ -3974,12 +3983,12 @@ class _ExitWidgetSelectionTooltipPainter extends CustomPainter { _ExitWidgetSelectionTooltipPainter({ required this.tooltipMessage, required this.buttonKey, - required this.isLeftAligned, + required this.usesDefaultAlignment, }); final String? tooltipMessage; final GlobalKey buttonKey; - final bool isLeftAligned; + final bool usesDefaultAlignment; @override void paint(Canvas canvas, Size size) { @@ -4021,7 +4030,7 @@ class _ExitWidgetSelectionTooltipPainter extends CustomPainter { final double tooltipHeight = textHeight + (tooltipPadding * 2); final double tooltipXOffset = - isLeftAligned ? 0 - buttonWidth : 0 - (tooltipWidth - buttonWidth); + usesDefaultAlignment ? 0 - buttonWidth : 0 - (tooltipWidth - buttonWidth); final double tooltipYOffset = 0 - tooltipHeight - tooltipSpacing; // Draw tooltip background. diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index 8e8ffc2fcf3c5..20f18e26d760e 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -420,7 +420,7 @@ class _RenderScaledInlineWidget extends RenderBox with RenderObjectWithChildMixi @override void applyPaintTransform(RenderBox child, Matrix4 transform) { - transform.scale(scale, scale); + transform.scaleByDouble(scale, scale, scale, 1); } @override diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 2a3d585f4a21f..efe2858c67443 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -104,6 +104,7 @@ export 'src/widgets/platform_view.dart'; export 'src/widgets/pop_scope.dart'; export 'src/widgets/preferred_size.dart'; export 'src/widgets/primary_scroll_controller.dart'; +export 'src/widgets/radio_group.dart'; export 'src/widgets/raw_keyboard_listener.dart'; export 'src/widgets/raw_menu_anchor.dart'; export 'src/widgets/raw_radio.dart'; diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 40dcf477c61e3..3654490d76367 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -5,6 +5,8 @@ homepage: https://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # @@ -14,7 +16,7 @@ dependencies: collection: 1.19.1 material_color_utilities: 0.11.1 meta: 1.16.0 - vector_math: 2.1.4 + vector_math: 2.2.0 sky_engine: sdk: flutter @@ -27,32 +29,15 @@ dev_dependencies: sdk: flutter flutter_localizations: sdk: flutter - fake_async: 1.3.3 + fake_async: any # To track memory leaks. - leak_tracker_flutter_testing: 3.0.10 - leak_tracker_testing: 3.0.2 - leak_tracker: 11.0.1 - web: 1.1.1 - - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - intl: 0.20.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + leak_tracker_flutter_testing: any + leak_tracker_testing: any + leak_tracker: any + web: any + clock: any + file: any + path: any + platform: any -# PUBSPEC CHECKSUM: b7a8 +# PUBSPEC CHECKSUM: i8s8fi diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index cccfc71560c67..2175d8edb2a4e 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -2846,14 +2846,6 @@ void main() { // Tap the search field. await tester.tap(find.byType(CupertinoSearchTextField), warnIfMissed: false); await tester.pump(); - // Pump halfway through the animation. - await tester.pump(const Duration(milliseconds: 150)); - - await expectLater( - find.byType(CupertinoSliverNavigationBar), - matchesGoldenFile('nav_bar.search.transition_forward.png'), - ); - // Pump to the end of the animation. await tester.pump(const Duration(milliseconds: 300)); @@ -2865,14 +2857,6 @@ void main() { // Tap the 'Cancel' button to exit the search view. await tester.tap(find.widgetWithText(CupertinoButton, 'Cancel')); await tester.pump(); - // Pump halfway through the animation. - await tester.pump(const Duration(milliseconds: 150)); - - await expectLater( - find.byType(CupertinoSliverNavigationBar), - matchesGoldenFile('nav_bar.search.transition_backward.png'), - ); - // Pump for the duration of the search field animation. await tester.pump(const Duration(milliseconds: 300)); diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index dec289f3f1b96..12c5b38db5119 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -1850,6 +1850,33 @@ void main() { expect(find.text('Page 2'), findsOneWidget); }); + testWidgets('Bottom large title is shown mid-transition when top has no leading', ( + WidgetTester tester, + ) async { + setWindowToPortrait(tester); + await startTransitionBetween( + tester, + from: const CupertinoSliverNavigationBar(largeTitle: Text('Page 1')), + to: const CupertinoSliverNavigationBar( + largeTitle: Text('Page 2'), + automaticallyImplyLeading: false, + ), + ); + + // Go to the next page. + await tester.pump(const Duration(milliseconds: 600)); + + // Start the gesture at the edge of the screen. + final TestGesture gesture = await tester.startGesture(const Offset(5.0, 200.0)); + // Trigger the swipe. + await gesture.moveBy(const Offset(200.0, 0.0)); + + // Back gestures should trigger and draw the hero transition in the very same + // frame (since the "from" route has already moved to reveal the "to" route). + await tester.pump(); + expect(flying(tester, find.text('Page 1')), findsOneWidget); + }); + testWidgets('Back label is not clipped mid-transition', (WidgetTester tester) async { const String label = 'backbackback'; await startTransitionBetween( diff --git a/packages/flutter/test/cupertino/radio_test.dart b/packages/flutter/test/cupertino/radio_test.dart index 967f7bf637a9c..7e049ac28ace2 100644 --- a/packages/flutter/test/cupertino/radio_test.dart +++ b/packages/flutter/test/cupertino/radio_test.dart @@ -53,17 +53,36 @@ void main() { expect(log, isEmpty); + await tester.pumpWidget( + CupertinoApp(home: Center(child: CupertinoRadio(key: key, value: 1, groupValue: 2))), + ); + + await tester.tap(find.byKey(key)); + + expect(log, isEmpty); + }); + + testWidgets('Radio disabled', (WidgetTester tester) async { + final Key key = UniqueKey(); + final List log = []; + await tester.pumpWidget( CupertinoApp( home: Center( - child: CupertinoRadio(key: key, value: 1, groupValue: 2, onChanged: null), + child: CupertinoRadio( + key: key, + value: 1, + groupValue: 2, + enabled: false, + onChanged: log.add, + ), ), ), ); await tester.tap(find.byKey(key)); - expect(log, isEmpty); + expect(log, equals([])); }); testWidgets('Radio can be toggled when toggleable is set', (WidgetTester tester) async { @@ -111,13 +130,7 @@ void main() { await tester.pumpWidget( CupertinoApp( home: Center( - child: CupertinoRadio( - key: key, - value: 1, - groupValue: null, - onChanged: log.add, - toggleable: true, - ), + child: CupertinoRadio(key: key, value: 1, onChanged: log.add, toggleable: true), ), ), ); @@ -204,9 +217,7 @@ void main() { ); await tester.pumpWidget( - const CupertinoApp( - home: Center(child: CupertinoRadio(value: 1, groupValue: 2, onChanged: null)), - ), + const CupertinoApp(home: Center(child: CupertinoRadio(value: 1, groupValue: 2))), ); expect( @@ -233,9 +244,7 @@ void main() { ); await tester.pumpWidget( - const CupertinoApp( - home: Center(child: CupertinoRadio(value: 2, groupValue: 2, onChanged: null)), - ), + const CupertinoApp(home: Center(child: CupertinoRadio(value: 2, groupValue: 2))), ); expect( @@ -531,7 +540,7 @@ void main() { return CupertinoApp( home: Center( child: RepaintBoundary( - child: CupertinoRadio(value: value, groupValue: groupValue, onChanged: null), + child: CupertinoRadio(value: value, groupValue: groupValue), ), ), ); @@ -558,7 +567,7 @@ void main() { theme: const CupertinoThemeData(brightness: Brightness.dark), home: Center( child: RepaintBoundary( - child: CupertinoRadio(value: value, groupValue: groupValue, onChanged: null), + child: CupertinoRadio(value: value, groupValue: groupValue), ), ), ); @@ -892,12 +901,7 @@ void main() { await tester.pumpWidget( const CupertinoApp( home: Center( - child: CupertinoRadio( - value: 1, - groupValue: 1, - onChanged: null, - mouseCursor: _RadioMouseCursor(), - ), + child: CupertinoRadio(value: 1, groupValue: 1, mouseCursor: _RadioMouseCursor()), ), ), ); diff --git a/packages/flutter/test/cupertino/search_field_test.dart b/packages/flutter/test/cupertino/search_field_test.dart index 03666fd90422b..237c9841ff296 100644 --- a/packages/flutter/test/cupertino/search_field_test.dart +++ b/packages/flutter/test/cupertino/search_field_test.dart @@ -129,7 +129,7 @@ void main() { ); Text placeholder = tester.widget(find.text('Search')); - expect(placeholder.style!.color!.value, CupertinoColors.systemGrey.darkColor.value); + expect(placeholder.style!.color!.value, CupertinoColors.secondaryLabel.darkColor.value); await tester.pumpAndSettle(); @@ -141,7 +141,7 @@ void main() { ); placeholder = tester.widget(find.text('Search')); - expect(placeholder.style!.color!.value, CupertinoColors.systemGrey.color.value); + expect(placeholder.style!.color!.value, CupertinoColors.secondaryLabel.color.value); }); testWidgets("placeholderStyle modifies placeholder's style and doesn't affect text's style", ( @@ -623,7 +623,7 @@ void main() { expect(suffixIconFinder, findsOneWidget); expect(placeholderFinder, findsOneWidget); - // Initially, the icons and placeholder text are fully opaque. + // Initially, the icons are fully opaque. expect( tester .widget(find.ancestor(of: prefixIconFinder, matching: find.byType(Opacity))) @@ -636,7 +636,8 @@ void main() { .opacity, equals(1.0), ); - expect(tester.widget(placeholderFinder).style?.color?.a, equals(1.0)); + // The default placeholder color is semi-transparent. + expect(tester.widget(placeholderFinder).style?.color?.a, equals(0.6)); final double searchTextFieldHeight = tester.getSize(searchTextFieldFinder).height; diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index af9e0565ea701..ee04f3d252472 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -425,7 +425,7 @@ void main() { // didChangeAccessibilityFeatures tester.platformDispatcher.accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - await tester.pump(); + await tester.pumpAndSettle(); expect(routeBuildCount, equals(1)); expect(dependentBuildCount, equals(5)); diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index fb4a8c4c192ed..f61208979fd44 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -2538,35 +2538,25 @@ void main() { flags: [SemanticsFlag.scopesRoute], children: [ TestSemantics( - children: [ - TestSemantics( - flags: [ - SemanticsFlag.isButton, - SemanticsFlag.isFocusable, - SemanticsFlag.hasSelectedState, - SemanticsFlag.isSelected, - ], - actions: [ - SemanticsAction.tap, - SemanticsAction.focus, - ], - label: 'A\nTab 1 of 2', - textDirection: TextDirection.ltr, - ), - TestSemantics( - flags: [ - SemanticsFlag.isButton, - SemanticsFlag.isFocusable, - SemanticsFlag.hasSelectedState, - ], - actions: [ - SemanticsAction.tap, - SemanticsAction.focus, - ], - label: 'B\nTab 2 of 2', - textDirection: TextDirection.ltr, - ), + flags: [ + SemanticsFlag.isButton, + SemanticsFlag.isFocusable, + SemanticsFlag.hasSelectedState, + SemanticsFlag.isSelected, ], + actions: [SemanticsAction.tap, SemanticsAction.focus], + label: 'A\nTab 1 of 2', + textDirection: TextDirection.ltr, + ), + TestSemantics( + flags: [ + SemanticsFlag.isButton, + SemanticsFlag.isFocusable, + SemanticsFlag.hasSelectedState, + ], + actions: [SemanticsAction.tap, SemanticsAction.focus], + label: 'B\nTab 2 of 2', + textDirection: TextDirection.ltr, ), ], ), diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index 3a4dad84a7c7c..b462b07b64749 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -1100,16 +1100,9 @@ void main() { flags: [SemanticsFlag.scopesRoute, SemanticsFlag.namesRoute], children: [ TestSemantics( + flags: [SemanticsFlag.hasImplicitScrolling], children: [ - TestSemantics( - flags: [SemanticsFlag.hasImplicitScrolling], - children: [ - TestSemantics( - label: 'BottomSheet', - textDirection: TextDirection.ltr, - ), - ], - ), + TestSemantics(label: 'BottomSheet', textDirection: TextDirection.ltr), ], ), ], @@ -1174,17 +1167,12 @@ void main() { flags: [SemanticsFlag.scopesRoute, SemanticsFlag.namesRoute], children: [ TestSemantics( - label: 'BottomSheet', + flags: [SemanticsFlag.isButton], + actions: [SemanticsAction.tap], + label: 'Dismiss', textDirection: TextDirection.ltr, - children: [ - TestSemantics( - flags: [SemanticsFlag.isButton], - actions: [SemanticsAction.tap], - label: 'Dismiss', - textDirection: TextDirection.ltr, - ), - ], ), + TestSemantics(label: 'BottomSheet', textDirection: TextDirection.ltr), ], ), ], diff --git a/packages/flutter/test/material/card_test.dart b/packages/flutter/test/material/card_test.dart index d049d87d049c2..770e2cc4ba6ef 100644 --- a/packages/flutter/test/material/card_test.dart +++ b/packages/flutter/test/material/card_test.dart @@ -101,25 +101,18 @@ void main() { hasSemantics( TestSemantics.root( children: [ + TestSemantics(id: 1, label: 'I am text!', textDirection: TextDirection.ltr), + TestSemantics(id: 2, label: 'Moar text!!1', textDirection: TextDirection.ltr), TestSemantics( - id: 1, - elevation: 1.0, - thickness: 0.0, - children: [ - TestSemantics(id: 2, label: 'I am text!', textDirection: TextDirection.ltr), - TestSemantics(id: 3, label: 'Moar text!!1', textDirection: TextDirection.ltr), - TestSemantics( - id: 4, - label: 'Button', - textDirection: TextDirection.ltr, - actions: [SemanticsAction.tap, SemanticsAction.focus], - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isButton, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - ], - ), + id: 3, + label: 'Button', + textDirection: TextDirection.ltr, + actions: [SemanticsAction.tap, SemanticsAction.focus], + flags: [ + SemanticsFlag.hasEnabledState, + SemanticsFlag.isButton, + SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable, ], ), ], diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index f7d16d5f56fd4..121c1ad8b0c68 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -1716,8 +1716,8 @@ Material _getMaterial(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index e47a3ff752f53..9784a929aa071 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -367,8 +367,8 @@ Material _barMaterial(WidgetTester tester) { ShapeDecoration? _indicator(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index fde25e676a604..667be62ebfa45 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -123,16 +123,14 @@ void main() { await tester.tap(find.text('AC')); await tester.pump(); - // When no background color is set, only the non-visible indicator Ink is expected. - expect(findDestinationInk('AC'), findsOne); + expect(findDestinationInk('AC'), findsNothing); // Destination with a custom background color. await tester.tap(find.byIcon(Icons.access_alarm)); await tester.pump(); // A Material is added with the custom color. - expect(findDestinationInk('Alarm'), findsNWidgets(2)); - // The drawer destination Ink is the first one, the second is the indicator's one. + expect(findDestinationInk('Alarm'), findsOne); final BoxDecoration destinationDecoration = tester.firstWidget(findDestinationInk('Alarm')).decoration! as BoxDecoration; expect(destinationDecoration.color, color); @@ -488,6 +486,46 @@ void main() { await tester.pumpAndSettle(); }); + + testWidgets('NavigationDrawer can display header and footer', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + widgetSetup(tester, 3000, viewHeight: 3000); + final Widget widget = _buildWidget( + scaffoldKey, + NavigationDrawer( + header: const DrawerHeader( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [FlutterLogo(), Text('Header')], + ), + ), + ), + footer: ListTile( + leading: const FlutterLogo(), + title: const Text('Footer'), + trailing: const Icon(Icons.settings), + onTap: () {}, + ), + children: [ + for (int i = 0; i < 10; i++) + NavigationDrawerDestination(icon: const Icon(Icons.home), label: Text('Item $i')), + ], + ), + ); + + await tester.pumpWidget(widget); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(const Duration(seconds: 1)); + + expect(find.byType(DrawerHeader), findsOneWidget); + expect(find.text('Header'), findsOneWidget); + expect(find.byType(FlutterLogo), findsNWidgets(2)); + expect(find.byType(ListTile), findsOneWidget); + expect(find.text('Footer'), findsOneWidget); + expect(find.byIcon(Icons.settings), findsOneWidget); + }); } Widget _buildWidget(GlobalKey scaffoldKey, Widget child, {bool? useMaterial3}) { @@ -511,8 +549,8 @@ InkWell? _getInkWell(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_drawer_theme_test.dart b/packages/flutter/test/material/navigation_drawer_theme_test.dart index 4a30bc8cf3b76..9ad94a8e8f3f3 100644 --- a/packages/flutter/test/material/navigation_drawer_theme_test.dart +++ b/packages/flutter/test/material/navigation_drawer_theme_test.dart @@ -285,8 +285,8 @@ Material _getMaterial(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 5e0e10631a138..b60893aa3ac82 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3076,7 +3076,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere( (RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures', ); - const Rect indicatorRect = Rect.fromLTRB(12.0, 0.0, 68.0, 32.0); const Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); @@ -3102,7 +3101,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(12.0, 0.0, 68.0, 32.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(12.0, 72.0, 68.0, 104.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3164,7 +3163,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(12.0, 6.0, 68.0, 38.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(12.0, 58.0, 68.0, 90.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3230,7 +3229,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(30.0, 24.0, 86.0, 56.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(30.0, 96.0, 86.0, 128.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3295,7 +3294,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(0.0, 6.0, 50.0, 38.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(0.0, 58.0, 50.0, 90.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3362,7 +3361,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(140.0, 24.0, 196.0, 56.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(140.0, 96.0, 196.0, 128.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3402,11 +3401,13 @@ void main() { ); // Default values from M3 specification. - const double railMinWidth = 80.0; const double indicatorHeight = 32.0; const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; // The navigation rail width is larger than default because of the first destination long label. final double railWidth = tester.getSize(find.byType(NavigationRail)).width; @@ -3417,7 +3418,13 @@ void main() { final Rect indicatorRect = Rect.fromLTRB(indicatorLeft, 0.0, indicatorRight, indicatorHeight); final Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); - const double indicatorHorizontalPadding = (railMinWidth - indicatorWidth) / 2; // 12.0 + + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = + indicatorHeight + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset; expect( inkFeatures, @@ -3441,10 +3448,10 @@ void main() { ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( rrect: RRect.fromLTRBR( - indicatorHorizontalPadding, - 0.0, - indicatorHorizontalPadding + indicatorWidth, - indicatorHeight, + indicatorLeft, + secondIndicatorVerticalOffset, + indicatorRight, + secondIndicatorVerticalOffset + indicatorHeight, const Radius.circular(16), ), color: const Color(0xffe8def8), @@ -3497,6 +3504,9 @@ void main() { const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; // The navigation rail width is the default one because labels are short. final double railWidth = tester.getSize(find.byType(NavigationRail)).width; @@ -3516,8 +3526,13 @@ void main() { final Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); - // Icon height is greater than indicator height so the indicator has a vertical offset. - const double secondIndicatorVerticalOffset = (iconSize - indicatorHeight) / 2; + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = + iconSize + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double indicatorOffset = (iconSize - indicatorHeight) / 2; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset + indicatorOffset; expect( inkFeatures, @@ -3596,6 +3611,7 @@ void main() { const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; const double verticalDestinationSpacingM3 = 12.0; // The navigation rail width is the default one because labels are short. @@ -3615,7 +3631,11 @@ void main() { final Rect excludedRect = includedRect.inflate(10); // Compute the vertical position for the selected destination (the one with 'bookmark' icon). - const double secondIndicatorVerticalOffset = verticalDestinationSpacingM3 / 2; + const double destinationHeight = indicatorHeight + verticalDestinationSpacingM3; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = + secondDestinationVerticalOffset + verticalDestinationSpacingM3 / 2; + const double secondDestinationHorizontalOffset = 800 - railMinExtendedWidth; // RTL. expect( inkFeatures, @@ -3641,9 +3661,9 @@ void main() { // Indicator for the selected destination (the one with 'bookmark' icon). ..rrect( rrect: RRect.fromLTRBR( - indicatorLeft, + secondDestinationHorizontalOffset + indicatorLeft, secondIndicatorVerticalOffset, - indicatorRight, + secondDestinationHorizontalOffset + indicatorRight, secondIndicatorVerticalOffset + indicatorHeight, const Radius.circular(16), ), @@ -6150,8 +6170,8 @@ Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false} ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_rail_theme_test.dart b/packages/flutter/test/material/navigation_rail_theme_test.dart index 07236c9e63347..49581b8ba90b3 100644 --- a/packages/flutter/test/material/navigation_rail_theme_test.dart +++ b/packages/flutter/test/material/navigation_rail_theme_test.dart @@ -327,8 +327,8 @@ Material _railMaterial(WidgetTester tester) { ShapeDecoration? _indicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(NavigationIndicator), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(NavigationIndicator), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart index dd75cc7f0edeb..1fd31952a27e4 100644 --- a/packages/flutter/test/material/radio_list_tile_test.dart +++ b/packages/flutter/test/material/radio_list_tile_test.dart @@ -27,8 +27,7 @@ void main() { int? selectedValue; // Constructor parameters are required for [RadioListTile], but they are // irrelevant when searching with [find.byType]. - final Type radioListTileType = - const RadioListTile(value: 0, groupValue: 0, onChanged: null).runtimeType; + final Type radioListTileType = const RadioListTile(value: 0, groupValue: 0).runtimeType; List> generatedRadioListTiles; List> findTiles() => @@ -126,7 +125,6 @@ void main() { key: key, value: 1, groupValue: 2, - onChanged: null, title: Text('Title', key: titleKey), ), ), @@ -158,7 +156,7 @@ void main() { int? selectedValue; // Constructor parameters are required for [Radio], but they are irrelevant // when searching with [find.byType]. - final Type radioType = const Radio(value: 0, groupValue: 0, onChanged: null).runtimeType; + final Type radioType = const Radio(value: 0, groupValue: 0).runtimeType; final List log = []; Widget buildFrame() { @@ -223,7 +221,7 @@ void main() { int? selectedValue; // Constructor parameters are required for [Radio], but they are irrelevant // when searching with [find.byType]. - final Type radioType = const Radio(value: 0, groupValue: 0, onChanged: null).runtimeType; + final Type radioType = const Radio(value: 0, groupValue: 0).runtimeType; final List log = []; Widget buildFrame() { @@ -273,7 +271,7 @@ void main() { int? selectedValue; // Constructor parameters are required for [Radio], but they are irrelevant // when searching with [find.byType]. - final Type radioType = const Radio(value: 0, groupValue: 0, onChanged: null).runtimeType; + final Type radioType = const Radio(value: 0, groupValue: 0).runtimeType; final List log = []; Widget buildFrame() { @@ -362,15 +360,7 @@ void main() { await tester.pumpWidget( Material( - child: Center( - child: Radio( - key: key, - value: 1, - groupValue: null, - onChanged: log.add, - toggleable: true, - ), - ), + child: Center(child: Radio(key: key, value: 1, onChanged: log.add, toggleable: true)), ), ); @@ -466,7 +456,6 @@ void main() { child: const RadioListTile( value: 1, groupValue: 2, - onChanged: null, title: Text('Title'), internalAddSemanticForOnTap: true, ), @@ -504,7 +493,6 @@ void main() { child: const RadioListTile( value: 2, groupValue: 2, - onChanged: null, title: Text('Title'), internalAddSemanticForOnTap: true, ), @@ -607,7 +595,6 @@ void main() { child: RadioListTile( value: 1, groupValue: 2, - onChanged: null, title: Text('Title', key: childKey), autofocus: true, ), @@ -619,8 +606,7 @@ void main() { }); testWidgets('RadioListTile contentPadding test', (WidgetTester tester) async { - final Type radioType = - const Radio(groupValue: true, value: true, onChanged: null).runtimeType; + final Type radioType = const Radio(groupValue: true, value: true).runtimeType; await tester.pumpWidget( wrap( @@ -666,7 +652,6 @@ void main() { child: RadioListTile( value: true, groupValue: true, - onChanged: null, title: Text('Title'), shape: shapeBorder, ), @@ -686,7 +671,6 @@ void main() { child: RadioListTile( value: false, groupValue: true, - onChanged: null, title: const Text('Title'), tileColor: tileColor, ), @@ -706,7 +690,6 @@ void main() { child: RadioListTile( value: false, groupValue: true, - onChanged: null, title: const Text('Title'), selected: true, selectedTileColor: selectedTileColor, @@ -887,7 +870,7 @@ void main() { wrap( child: const MouseRegion( cursor: SystemMouseCursors.forbidden, - child: RadioListTile(value: 1, onChanged: null, groupValue: 2), + child: RadioListTile(value: 1, groupValue: 2), ), ), ); @@ -1610,9 +1593,7 @@ void main() { testWidgets('RadioListTile renders with default scale', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( - home: Material( - child: RadioListTile(value: false, groupValue: false, onChanged: null), - ), + home: Material(child: RadioListTile(value: false, groupValue: false)), ), ); @@ -1629,12 +1610,7 @@ void main() { await tester.pumpWidget( const MaterialApp( home: Material( - child: RadioListTile( - value: false, - groupValue: false, - onChanged: null, - radioScaleFactor: scale, - ), + child: RadioListTile(value: false, groupValue: false, radioScaleFactor: scale), ), ), ); @@ -1668,7 +1644,6 @@ void main() { title: const Text('A'), subtitle: const Text('A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM'), value: 0, - onChanged: null, groupValue: 1, ), RadioListTile( @@ -1676,7 +1651,6 @@ void main() { title: const Text('A'), subtitle: const Text('A'), value: 0, - onChanged: null, groupValue: 2, ), ], @@ -1787,7 +1761,6 @@ void main() { title: const Text('A'), subtitle: const Text('A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM'), value: 0, - onChanged: null, groupValue: 1, ), RadioListTile.adaptive( @@ -1795,7 +1768,6 @@ void main() { title: const Text('A'), subtitle: const Text('A'), value: 0, - onChanged: null, groupValue: 2, ), ], diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 283be4b5510d7..b05d31b7ff4f9 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -60,18 +60,42 @@ void main() { expect(log, isEmpty); + await tester.pumpWidget( + Theme( + data: theme, + child: Material(child: Center(child: Radio(key: key, value: 1, groupValue: 2))), + ), + ); + + await tester.tap(find.byKey(key)); + + expect(log, isEmpty); + }); + + testWidgets('Radio disabled', (WidgetTester tester) async { + final Key key = UniqueKey(); + final List log = []; + await tester.pumpWidget( Theme( data: theme, child: Material( - child: Center(child: Radio(key: key, value: 1, groupValue: 2, onChanged: null)), + child: Center( + child: Radio( + key: key, + value: 1, + groupValue: 2, + enabled: false, + onChanged: log.add, + ), + ), ), ), ); await tester.tap(find.byKey(key)); - expect(log, isEmpty); + expect(log, equals([])); }); testWidgets('Radio can be toggled when toggleable is set', (WidgetTester tester) async { @@ -127,13 +151,7 @@ void main() { data: theme, child: Material( child: Center( - child: Radio( - key: key, - value: 1, - groupValue: null, - onChanged: log.add, - toggleable: true, - ), + child: Radio(key: key, value: 1, onChanged: log.add, toggleable: true), ), ), ), @@ -291,10 +309,7 @@ void main() { ); await tester.pumpWidget( - Theme( - data: theme, - child: const Material(child: Radio(value: 1, groupValue: 2, onChanged: null)), - ), + Theme(data: theme, child: const Material(child: Radio(value: 1, groupValue: 2))), ); expect( @@ -343,10 +358,7 @@ void main() { ); await tester.pumpWidget( - Theme( - data: theme, - child: const Material(child: Radio(value: 2, groupValue: 2, onChanged: null)), - ), + Theme(data: theme, child: const Material(child: Radio(value: 2, groupValue: 2))), ); expect( @@ -1091,7 +1103,7 @@ void main() { child: Material( child: MouseRegion( cursor: SystemMouseCursors.forbidden, - child: Radio(value: 1, onChanged: null, groupValue: 2), + child: Radio(value: 1, groupValue: 2), ), ), ), @@ -1566,7 +1578,7 @@ void main() { home: const Material( child: Tooltip( message: longPressTooltip, - child: Radio(value: true, groupValue: false, onChanged: null), + child: Radio(value: true, groupValue: false), ), ), ), @@ -1596,7 +1608,7 @@ void main() { child: Tooltip( triggerMode: TooltipTriggerMode.tap, message: tapTooltip, - child: Radio(value: true, groupValue: false, onChanged: null), + child: Radio(value: true, groupValue: false), ), ), ), diff --git a/packages/flutter/test/painting/alignment_test.dart b/packages/flutter/test/painting/alignment_test.dart index fa6612087d8f7..815723b1934d7 100644 --- a/packages/flutter/test/painting/alignment_test.dart +++ b/packages/flutter/test/painting/alignment_test.dart @@ -338,4 +338,16 @@ void main() { expect(const AlignmentGeometry.xy(4, 5), const Alignment(4, 5)); expect(const AlignmentGeometry.directional(4, 5), const AlignmentDirectional(4, 5)); }); + + test('AlignmentGeometry static members', () { + expect(AlignmentGeometry.topLeft, Alignment.topLeft); + expect(AlignmentGeometry.topCenter, Alignment.topCenter); + expect(AlignmentGeometry.topRight, Alignment.topRight); + expect(AlignmentGeometry.centerLeft, Alignment.centerLeft); + expect(AlignmentGeometry.center, Alignment.center); + expect(AlignmentGeometry.centerRight, Alignment.centerRight); + expect(AlignmentGeometry.bottomLeft, Alignment.bottomLeft); + expect(AlignmentGeometry.bottomCenter, Alignment.bottomCenter); + expect(AlignmentGeometry.bottomRight, Alignment.bottomRight); + }); } diff --git a/packages/flutter/test/painting/text_painter_rtl_test.dart b/packages/flutter/test/painting/text_painter_rtl_test.dart index 47915266e2dea..6632555b9dac4 100644 --- a/packages/flutter/test/painting/text_painter_rtl_test.dart +++ b/packages/flutter/test/painting/text_painter_rtl_test.dart @@ -383,7 +383,7 @@ void main() { ], ); painter.dispose(); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/32238 + }); test('TextPainter - line wrap mid-word', () { final TextPainter painter = TextPainter()..textDirection = TextDirection.ltr; diff --git a/packages/flutter/test/semantics/semantics_elevation_test.dart b/packages/flutter/test/semantics/semantics_elevation_test.dart deleted file mode 100644 index e6a3a86fd2bc5..0000000000000 --- a/packages/flutter/test/semantics/semantics_elevation_test.dart +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../widgets/semantics_tester.dart'; - -void main() { - testWidgets('SemanticsNodes overlapping in z', (WidgetTester tester) async { - // Cards are semantic boundaries that always own their own SemanticNode, - // PhysicalModels merge their semantics information into parent. - // - // Side view of the widget tree: - // - // Card('abs. elevation: 30') --------------- - // | 8 ----------- Card('abs. elevation 25') - // Card('abs. elevation: 22') --------------- | - // | 7 | - // PhysicalModel('abs. elevation: 15') --------------- | 15 - // | 5 | - // --------------------------------------- Card('abs. elevation: 10') - // | 10 - // | - // --------------------------------------- 'ground' - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - const MaterialApp( - home: Column( - children: [ - Text('ground'), - Card( - elevation: 10.0, - child: Column( - children: [ - Text('absolute elevation: 10'), - PhysicalModel( - elevation: 5.0, - color: Colors.black, - child: Column( - children: [ - Text('absolute elevation: 15'), - Card( - elevation: 7.0, - child: Column( - children: [ - Text('absolute elevation: 22'), - Card(elevation: 8.0, child: Text('absolute elevation: 30')), - ], - ), - ), - ], - ), - ), - Card(elevation: 15.0, child: Text('absolute elevation: 25')), - ], - ), - ), - ], - ), - ), - ); - - final SemanticsNode ground = tester.getSemantics(find.text('ground')); - expect(ground.thickness, 0.0); - expect(ground.elevation, 0.0); - expect(ground.label, 'ground'); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); - final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); - expect(elevation10, same(elevation15)); // configs got merged into each other. - expect(elevation10.thickness, 15.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'absolute elevation: 10\nabsolute elevation: 15'); - - final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); - expect(elevation22.thickness, 7.0); - expect(elevation22.elevation, 15.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); - expect(elevation25.thickness, 15.0); - expect(elevation25.elevation, 10.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); - expect(elevation30.thickness, 8.0); - expect(elevation30.elevation, 7.0); - expect(elevation30.label, 'absolute elevation: 30'); - - semantics.dispose(); - }); - - testWidgets('SemanticsNodes overlapping in z with switched children', ( - WidgetTester tester, - ) async { - // Same as 'SemanticsNodes overlapping in z', but the order of children - // is reversed - - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - const MaterialApp( - home: Column( - children: [ - Text('ground'), - Card( - elevation: 10.0, - child: Column( - children: [ - Card(elevation: 15.0, child: Text('absolute elevation: 25')), - PhysicalModel( - elevation: 5.0, - color: Colors.black, - child: Column( - children: [ - Text('absolute elevation: 15'), - Card( - elevation: 7.0, - child: Column( - children: [ - Text('absolute elevation: 22'), - Card(elevation: 8.0, child: Text('absolute elevation: 30')), - ], - ), - ), - ], - ), - ), - Text('absolute elevation: 10'), - ], - ), - ), - ], - ), - ), - ); - - final SemanticsNode ground = tester.getSemantics(find.text('ground')); - expect(ground.thickness, 0.0); - expect(ground.elevation, 0.0); - expect(ground.label, 'ground'); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); - final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); - expect(elevation10, same(elevation15)); // configs got merged into each other. - expect(elevation10.thickness, 15.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'absolute elevation: 15\nabsolute elevation: 10'); - - final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); - expect(elevation22.thickness, 7.0); - expect(elevation22.elevation, 15.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); - expect(elevation25.thickness, 15.0); - expect(elevation25.elevation, 10.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); - expect(elevation30.thickness, 8.0); - expect(elevation30.elevation, 7.0); - expect(elevation30.label, 'absolute elevation: 30'); - - semantics.dispose(); - }); - - testWidgets('single node thickness', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - const MaterialApp(home: Center(child: Material(elevation: 24.0, child: Text('Hello')))), - ); - - final SemanticsNode node = tester.getSemantics(find.text('Hello')); - expect(node.thickness, 0.0); - expect(node.elevation, 24.0); - expect(node.label, 'Hello'); - - semantics.dispose(); - }); - - testWidgets('force-merge', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - MaterialApp( - home: Card( - elevation: 10.0, - child: Column( - children: [ - const Text('abs. elevation: 10.0'), - MergeSemantics( - child: Semantics( - explicitChildNodes: - true, // just to be sure that it's going to be an explicit merge - child: const Column( - children: [ - Card(elevation: 15.0, child: Text('abs. elevation 25.0')), - Card(elevation: 5.0, child: Text('abs. elevation 15.0')), - ], - ), - ), - ), - ], - ), - ), - ), - ); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); - expect(elevation10.thickness, 10.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'abs. elevation: 10.0'); - expect(elevation10.childrenCount, 1); - - // TODO(goderbauer): remove awkward workaround when accessing force-merged - // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 - SemanticsData? mergedChildData; - elevation10.visitChildren((SemanticsNode child) { - expect(mergedChildData, isNull); - mergedChildData = child.getSemanticsData(); - return true; - }); - - expect(mergedChildData!.thickness, 15.0); - expect(mergedChildData!.elevation, 10.0); - expect(mergedChildData!.label, 'abs. elevation 25.0\nabs. elevation 15.0'); - - semantics.dispose(); - }); - - testWidgets('force-merge with inversed children', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - MaterialApp( - home: Card( - elevation: 10.0, - child: Column( - children: [ - const Text('abs. elevation: 10.0'), - MergeSemantics( - child: Semantics( - explicitChildNodes: - true, // just to be sure that it's going to be an explicit merge - child: const Column( - children: [ - Card(elevation: 5.0, child: Text('abs. elevation 15.0')), - Card(elevation: 15.0, child: Text('abs. elevation 25.0')), - ], - ), - ), - ), - ], - ), - ), - ), - ); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); - expect(elevation10.thickness, 10.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'abs. elevation: 10.0'); - expect(elevation10.childrenCount, 1); - - // TODO(goderbauer): remove awkward workaround when accessing force-merged - // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 - SemanticsData? mergedChildData; - elevation10.visitChildren((SemanticsNode child) { - expect(mergedChildData, isNull); - mergedChildData = child.getSemanticsData(); - return true; - }); - - expect(mergedChildData!.thickness, 15.0); - expect(mergedChildData!.elevation, 10.0); - expect(mergedChildData!.label, 'abs. elevation 15.0\nabs. elevation 25.0'); - - semantics.dispose(); - }); -} diff --git a/packages/flutter/test/semantics/semantics_test.dart b/packages/flutter/test/semantics/semantics_test.dart index b7129d9566732..ae9bb8e104af4 100644 --- a/packages/flutter/test/semantics/semantics_test.dart +++ b/packages/flutter/test/semantics/semantics_test.dart @@ -731,8 +731,6 @@ void main() { ' scrollPosition: null\n' ' scrollExtentMax: null\n' ' indexInParent: null\n' - ' elevation: 0.0\n' - ' thickness: 0.0\n' ' headingLevel: 0\n', ); @@ -867,8 +865,6 @@ void main() { ' scrollPosition: null\n' ' scrollExtentMax: null\n' ' indexInParent: null\n' - ' elevation: 0.0\n' - ' thickness: 0.0\n' ' headingLevel: 0\n', ); }); diff --git a/packages/flutter/test/semantics/semantics_update_test.dart b/packages/flutter/test/semantics/semantics_update_test.dart index 8f6c7d6c3d4f0..02e9804f464e3 100644 --- a/packages/flutter/test/semantics/semantics_update_test.dart +++ b/packages/flutter/test/semantics/semantics_update_test.dart @@ -206,8 +206,6 @@ class SemanticsUpdateBuilderSpy extends Fake implements ui.SemanticsUpdateBuilde required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, diff --git a/packages/flutter/test/widgets/editable_text_shortcuts_test.dart b/packages/flutter/test/widgets/editable_text_shortcuts_test.dart index fe49f4e7bf493..d88e0e201dcaa 100644 --- a/packages/flutter/test/widgets/editable_text_shortcuts_test.dart +++ b/packages/flutter/test/widgets/editable_text_shortcuts_test.dart @@ -2864,4 +2864,163 @@ void main() { ); }); }, skip: !kIsWeb); // [intended] specific tests target web. + + group( + 'Web does not accept', + () { + testWidgets('character modifier + arrowLeft in composing', (WidgetTester tester) async { + const SingleActivator arrowLeft = SingleActivator( + LogicalKeyboardKey.arrowLeft, + shift: true, + ); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, arrowLeft); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: arrowLeft.toString(), + ); + }); + + testWidgets('character modifier + arrowRight in composing', (WidgetTester tester) async { + const SingleActivator arrowRight = SingleActivator( + LogicalKeyboardKey.arrowLeft, + shift: true, + ); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, arrowRight); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: arrowRight.toString(), + ); + }); + + testWidgets('character modifier + arrowUp in composing', (WidgetTester tester) async { + const SingleActivator arrowUp = SingleActivator(LogicalKeyboardKey.arrowUp, shift: true); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, arrowUp); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: arrowUp.toString(), + ); + }); + + testWidgets('character modifier + arrowDown in composing', (WidgetTester tester) async { + const SingleActivator arrowDown = SingleActivator( + LogicalKeyboardKey.arrowDown, + shift: true, + ); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, arrowDown); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: arrowDown.toString(), + ); + }); + + testWidgets('home in composing', (WidgetTester tester) async { + const SingleActivator home = SingleActivator(LogicalKeyboardKey.home); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, home); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: home.toString(), + ); + }); + + testWidgets('end in composing', (WidgetTester tester) async { + const SingleActivator end = SingleActivator(LogicalKeyboardKey.end); + + controller.value = const TextEditingValue( + text: testText, + selection: TextSelection(baseOffset: 0, extentOffset: 3), + composing: TextRange(start: 0, end: 3), + ); + + await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 12))); + await tester.pumpAndSettle(); + + await sendKeyCombination(tester, end); + await tester.pump(); + + // selection should not change. + expect(controller.text, testText); + expect( + controller.selection, + const TextSelection(baseOffset: 0, extentOffset: 3), + reason: end.toString(), + ); + }); + }, + skip: !kIsWeb, // [intended] specific tests target web. + ); } diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart index 83902f38fb80b..26ab66d4744ee 100644 --- a/packages/flutter/test/widgets/heroes_test.dart +++ b/packages/flutter/test/widgets/heroes_test.dart @@ -216,6 +216,73 @@ class MyStatefulWidgetState extends State { Widget build(BuildContext context) => Text(widget.value); } +class DeepLinkApp extends StatefulWidget { + const DeepLinkApp({super.key}); + + static const CupertinoPage _homeScreen = CupertinoPage( + name: '/', + child: CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar(middle: Text('First')), + child: Center(child: Text('Home Screen')), + ), + ); + static const CupertinoPage _middleScreen = CupertinoPage( + name: '/middle', + child: CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar(middle: Text('Second')), + child: Center(child: Text('Middle Screen')), + ), + ); + static const CupertinoPage _lastScreen = CupertinoPage( + name: '/middle/last', + child: CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar(middle: Text('Third')), + child: Center(child: Text('Last Screen')), + ), + ); + + @override + DeepLinkAppState createState() => DeepLinkAppState(); +} + +class DeepLinkAppState extends State { + late List> _pages; + + @override + void initState() { + super.initState(); + _pages = >[DeepLinkApp._homeScreen]; + } + + void goToDeepScreen() { + setState(() { + _pages = >[ + DeepLinkApp._homeScreen, + DeepLinkApp._middleScreen, + DeepLinkApp._lastScreen, + ]; + }); + } + + @override + Widget build(BuildContext context) { + return CupertinoApp( + builder: (BuildContext context, Widget? child) { + return Navigator( + pages: _pages, + onDidRemovePage: (Page page) { + setState(() { + if (_pages.length > 1) { + _pages = List>.from(_pages)..removeLast(); + } + }); + }, + ); + }, + ); + } +} + Future main() async { final ui.Image testImage = await createTestImage(); @@ -2984,6 +3051,41 @@ Future main() async { }), ); + // Regression test for https://github.com/flutter/flutter/issues/168267. + testWidgets('Check if previous page is laid out on backswipe gesture before flight', ( + WidgetTester tester, + ) async { + final GlobalKey appKey = GlobalKey(); + await tester.pumpWidget(DeepLinkApp(key: appKey)); + + await tester.pumpAndSettle(); + + expect(find.text('Home Screen'), findsOneWidget); + expect(find.text('Last Screen'), findsNothing); + + appKey.currentState?.goToDeepScreen(); + + await tester.pumpAndSettle(); + + expect(find.text('Home Screen'), findsNothing); + expect(find.text('Last Screen'), findsOneWidget); + + final TestGesture gesture = await tester.startGesture(const Offset(0.01, 300)); + + await gesture.moveTo(const Offset(10, 300)); + await tester.pump(); + // Should not throw an assert here for size and finite space. + await gesture.moveTo(const Offset(500, 300)); + await tester.pump(); + + await gesture.up(); + await tester.pumpAndSettle(); + + expect(find.text('Home Screen'), findsNothing); + expect(find.text('Middle Screen'), findsOneWidget); + expect(find.text('Last Screen'), findsNothing); + }); + // Regression test for https://github.com/flutter/flutter/issues/40239. testWidgets( 'In a pop transition, when fromHero is null, the to hero should eventually become visible', diff --git a/packages/flutter/test/widgets/layout_builder_test.dart b/packages/flutter/test/widgets/layout_builder_test.dart index 2133ab111ff1a..e9d267c992913 100644 --- a/packages/flutter/test/widgets/layout_builder_test.dart +++ b/packages/flutter/test/widgets/layout_builder_test.dart @@ -984,6 +984,60 @@ void main() { await tester.pump(); expect(rebuilt, isTrue); }); + + testWidgets('LayoutBuilder does not crash when it becomes kept-alive', ( + WidgetTester tester, + ) async { + final FocusNode focusNode = FocusNode(); + final TextEditingController controller = TextEditingController(); + addTearDown(focusNode.dispose); + addTearDown(controller.dispose); + final Widget layoutBuilderWithParent = SizedBox( + key: GlobalKey(), + child: LayoutBuilder( + builder: (BuildContext _, BoxConstraints _) { + // The text field keeps the widget alive in the SliverList. + return EditableText( + focusNode: focusNode, + backgroundCursorColor: const Color(0xFFFFFFFF), + cursorColor: const Color(0xFFFFFFFF), + style: const TextStyle(), + controller: controller, + ); + }, + ), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CustomScrollView( + slivers: [ + SliverList.list( + addRepaintBoundaries: false, + addSemanticIndexes: false, + children: [const SizedBox(height: 60), layoutBuilderWithParent], + ), + ], + ), + ), + ); + focusNode.requestFocus(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: CustomScrollView( + slivers: [ + SliverList.list( + addRepaintBoundaries: false, + addSemanticIndexes: false, + children: [const SizedBox(height: 6000), layoutBuilderWithParent], + ), + ], + ), + ), + ); + }); } class _SmartLayoutBuilder extends ConstrainedLayoutBuilder { diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 8ca9fddcf8bc2..6f671c3841bb2 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -451,7 +451,7 @@ void main() { expect(data.accessibleNavigation, true); tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); - await tester.pump(); + await tester.pumpAndSettle(); expect(data.accessibleNavigation, false); expect(rebuildCount, 4); @@ -512,7 +512,7 @@ void main() { expect(data.accessibleNavigation, true); tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); - await tester.pump(); + await tester.pumpAndSettle(); expect(data.accessibleNavigation, true); expect(rebuildCount, 1); diff --git a/packages/flutter/test/widgets/radio_group_test.dart b/packages/flutter/test/widgets/radio_group_test.dart new file mode 100644 index 0000000000000..f69895e0c3623 --- /dev/null +++ b/packages/flutter/test/widgets/radio_group_test.dart @@ -0,0 +1,248 @@ +// Copyright 2014 The Flutter Authors. 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_test/flutter_test.dart'; + +void main() { + testWidgets('Radio group control test', (WidgetTester tester) async { + final UniqueKey key0 = UniqueKey(); + final UniqueKey key1 = UniqueKey(); + + await tester.pumpWidget( + Material( + child: TestRadioGroup( + child: Column( + children: [Radio(key: key0, value: 0), Radio(key: key1, value: 1)], + ), + ), + ), + ); + expect( + tester.getSemantics(find.byKey(key0)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + expect( + tester.getSemantics(find.byKey(key1)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + + await tester.tap(find.byKey(key0)); + await tester.pumpAndSettle(); + expect( + tester.getSemantics(find.byKey(key0)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: true, isEnabled: true), + ); + expect( + tester.getSemantics(find.byKey(key1)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + + await tester.tap(find.byKey(key1)); + await tester.pumpAndSettle(); + expect( + tester.getSemantics(find.byKey(key0)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + expect( + tester.getSemantics(find.byKey(key1)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: true, isEnabled: true), + ); + }); + + testWidgets('Radio group can have disabled radio', (WidgetTester tester) async { + final UniqueKey key0 = UniqueKey(); + final UniqueKey key1 = UniqueKey(); + + await tester.pumpWidget( + Material( + child: TestRadioGroup( + child: Column( + children: [ + Radio(key: key0, value: 0, enabled: false), + Radio(key: key1, value: 1), + ], + ), + ), + ), + ); + expect( + tester.getSemantics(find.byKey(key0)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: false), + ); + expect( + tester.getSemantics(find.byKey(key1)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + + await tester.tap(find.byKey(key0)); + await tester.pumpAndSettle(); + // Can't be select because the radio is disabled. + expect( + tester.getSemantics(find.byKey(key0)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: false), + ); + expect( + tester.getSemantics(find.byKey(key1)), + containsSemantics(isInMutuallyExclusiveGroup: true, isChecked: false, isEnabled: true), + ); + }); + + testWidgets('Radio group can use arrow key', (WidgetTester tester) async { + final UniqueKey key0 = UniqueKey(); + final UniqueKey key1 = UniqueKey(); + final UniqueKey key2 = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TestRadioGroup( + child: Column( + children: [ + Radio(key: key0, focusNode: focusNode, value: 0), + Radio(key: key1, value: 1), + Radio(key: key2, value: 2), + ], + ), + ), + ), + ), + ); + + final TestRadioGroupState state = tester.state>( + find.byType(TestRadioGroup), + ); + + await tester.tap(find.byKey(key0)); + focusNode.requestFocus(); + await tester.pumpAndSettle(); + expect(state.groupValue, 0); + expect(focusNode.hasFocus, isTrue); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pumpAndSettle(); + expect(state.groupValue, 1); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + expect(state.groupValue, 2); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pumpAndSettle(); + // Wrap around + expect(state.groupValue, 0); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft); + await tester.pumpAndSettle(); + // Wrap around + expect(state.groupValue, 2); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); + await tester.pumpAndSettle(); + // Wrap around + expect(state.groupValue, 1); + }); + + testWidgets('Radio group can tab in and out', (WidgetTester tester) async { + final UniqueKey key0 = UniqueKey(); + final UniqueKey key1 = UniqueKey(); + final UniqueKey key2 = UniqueKey(); + final FocusNode radio0 = FocusNode(); + addTearDown(radio0.dispose); + final FocusNode radio1 = FocusNode(); + addTearDown(radio1.dispose); + final FocusNode textFieldBefore = FocusNode(); + addTearDown(textFieldBefore.dispose); + final FocusNode textFieldAfter = FocusNode(); + addTearDown(textFieldAfter.dispose); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Column( + children: [ + TextField(focusNode: textFieldBefore), + TestRadioGroup( + child: Column( + children: [ + Radio(key: key0, focusNode: radio0, value: 0), + Radio(key: key1, focusNode: radio1, value: 1), + Radio(key: key2, value: 2), + ], + ), + ), + TextField(focusNode: textFieldAfter), + ], + ), + ), + ), + ); + + textFieldBefore.requestFocus(); + await tester.pump(); + expect(textFieldBefore.hasFocus, isTrue); + + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + // If no selected radio, focus the first. + expect(textFieldBefore.hasFocus, isFalse); + expect(radio0.hasFocus, isTrue); + + // tab out the radio group. + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + expect(radio0.hasFocus, isFalse); + expect(radio1.hasFocus, isFalse); + expect(textFieldAfter.hasFocus, isTrue); + + // Select the radio 1 + await tester.tap(find.byKey(key1)); + await tester.pump(); + final TestRadioGroupState state = tester.state>( + find.byType(TestRadioGroup), + ); + expect(state.groupValue, 1); + // focus textFieldAfter again. + textFieldAfter.requestFocus(); + await tester.pump(); + expect(textFieldAfter.hasFocus, isTrue); + + // shift+tab in the radio again. + await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.sendKeyUpEvent(LogicalKeyboardKey.shift); + await tester.pump(); + // Should focus selected radio + expect(radio0.hasFocus, isFalse); + expect(radio1.hasFocus, isTrue); + expect(textFieldAfter.hasFocus, isFalse); + }); +} + +class TestRadioGroup extends StatefulWidget { + const TestRadioGroup({super.key, required this.child}); + + final Widget child; + + @override + State createState() => TestRadioGroupState(); +} + +class TestRadioGroupState extends State> { + T? groupValue; + + @override + Widget build(BuildContext context) { + return RadioGroup( + onChanged: (T? newValue) { + setState(() { + groupValue = newValue; + }); + }, + groupValue: groupValue, + child: widget.child, + ); + } +} diff --git a/packages/flutter/test/widgets/raw_radio_test.dart b/packages/flutter/test/widgets/raw_radio_test.dart index 6e15105310036..19faf69b74816 100644 --- a/packages/flutter/test/widgets/raw_radio_test.dart +++ b/packages/flutter/test/widgets/raw_radio_test.dart @@ -14,20 +14,18 @@ void main() { testWidgets('RawRadio control test', (WidgetTester tester) async { final FocusNode node = FocusNode(); addTearDown(node.dispose); - int? actualValue; ToggleableStateMixin? actualState; + final TestRegistry registry = TestRegistry(); Widget buildWidget() { return RawRadio( value: 0, - groupValue: actualValue, - onChanged: (int? value) { - actualValue = value; - }, mouseCursor: WidgetStateProperty.all(SystemMouseCursors.click), toggleable: true, focusNode: node, autofocus: false, + enabled: true, + groupRegistry: registry, builder: (BuildContext context, ToggleableStateMixin state) { actualState = state; return CustomPaint(size: const Size(40, 40), painter: TestPainter()); @@ -38,14 +36,88 @@ void main() { await tester.pumpWidget(buildWidget()); expect(actualState!.tristate, isTrue); expect(actualState!.value, isFalse); + expect(registry.groupValue, isNull); + + final State state = tester.state(find.byType(RawRadio)); + expect(registry.clients.contains(state as RadioClient), isTrue); await tester.tap(find.byType(RawRadio)); // Rebuilds with new group value await tester.pumpWidget(buildWidget()); - expect(actualValue, 0); + expect(registry.groupValue, 0); expect(actualState!.value, isTrue); }); + + testWidgets('RawRadio disabled', (WidgetTester tester) async { + final FocusNode node = FocusNode(); + addTearDown(node.dispose); + final TestRegistry registry = TestRegistry(); + + Widget buildWidget() { + return RawRadio( + value: 0, + mouseCursor: WidgetStateProperty.all(SystemMouseCursors.click), + toggleable: true, + focusNode: node, + autofocus: false, + enabled: false, + groupRegistry: registry, + builder: (BuildContext context, ToggleableStateMixin state) { + return CustomPaint(size: const Size(40, 40), painter: TestPainter()); + }, + ); + } + + await tester.pumpWidget(buildWidget()); + await tester.tap(find.byType(RawRadio)); + // onChanged won't fire + expect(registry.groupValue, isNull); + }); + + testWidgets('RawRadio enabled without registry throws', (WidgetTester tester) async { + final FocusNode node = FocusNode(); + addTearDown(node.dispose); + + Widget buildWidget() { + return RawRadio( + value: 0, + mouseCursor: WidgetStateProperty.all(SystemMouseCursors.click), + toggleable: true, + focusNode: node, + autofocus: false, + enabled: true, + groupRegistry: null, + builder: (BuildContext context, ToggleableStateMixin state) { + return CustomPaint(size: const Size(40, 40), painter: TestPainter()); + }, + ); + } + + Object? error; + try { + await tester.pumpWidget(buildWidget()); + } catch (e) { + error = e; + } + + expect(error, isA()); + }); +} + +class TestRegistry extends RadioGroupRegistry { + final Set> clients = >{}; + @override + T? groupValue; + + @override + ValueChanged get onChanged => (T? newValue) => groupValue = newValue; + + @override + void registerClient(RadioClient radio) => clients.add(radio); + + @override + void unregisterClient(RadioClient radio) => clients.remove(radio); } class TestPainter extends CustomPainter { diff --git a/packages/flutter/test/widgets/routes_test.dart b/packages/flutter/test/widgets/routes_test.dart index 435ef8492e3ee..4c7afb8c7855b 100644 --- a/packages/flutter/test/widgets/routes_test.dart +++ b/packages/flutter/test/widgets/routes_test.dart @@ -2512,6 +2512,135 @@ void main() { moreOrLessEquals(xLocationIntervalTwelve, epsilon: 0.1), ); }); + + testWidgets('ModalRoute.isFirstOf only rebuilds when first route state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isFirst = ModalRoute.isFirstOf(context) ?? false; + return Text('isFirst: $isFirst'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isFirst: true'), findsOneWidget); + + // Push a new route - first route should remain first + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isFirst hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.isActiveOf only rebuilds when route active state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isActive = ModalRoute.isActiveOf(context) ?? false; + return Text('isActive: $isActive'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isActive: true'), findsOneWidget); + + // Push a new route - first route should remain active + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isActive hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.opaqueOf only rebuilds when route opaque state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isOpaque = ModalRoute.opaqueOf(context) ?? false; + return Text('isOpaque: $isOpaque'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isOpaque: true'), findsOneWidget); + + // Push a new route - first route should remain opaque + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isOpaque hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.popDispositionOf rebuilds when PopEntry affects pop disposition', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final RoutePopDisposition? popDisposition = ModalRoute.popDispositionOf(context); + return Text('popDisposition: ${popDisposition?.name}'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('popDisposition: bubble'), findsOneWidget); + + // Change PopScope's canPop to false + await tester.pumpWidget( + MaterialApp( + navigatorKey: navigator, + home: PopScope(canPop: false, child: Builder(builder: buildCounter)), + ), + ); + await tester.pumpAndSettle(); + + // Should rebuild because popDisposition changed to doNotPop + expect(buildCount, 2); + expect(find.text('popDisposition: doNotPop'), findsOneWidget); + + // Push a new route - should change from bubble to pop + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Shouldn't rebuild because popDisposition hasn't changed + expect(buildCount, 2); + }); }); testWidgets('can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/scrollable_selection_test.dart b/packages/flutter/test/widgets/scrollable_selection_test.dart index a21bf8f35da5e..807e40e8567d1 100644 --- a/packages/flutter/test/widgets/scrollable_selection_test.dart +++ b/packages/flutter/test/widgets/scrollable_selection_test.dart @@ -4,7 +4,6 @@ import 'dart:ui' as ui; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -188,7 +187,7 @@ void main() { expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on double-click drag - horizontal', ( WidgetTester tester, @@ -238,7 +237,7 @@ void main() { expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on triple-click drag', ( WidgetTester tester, @@ -310,7 +309,7 @@ void main() { expect(paragraph4.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on triple-click drag - horizontal', ( WidgetTester tester, @@ -372,7 +371,7 @@ void main() { expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('select to scroll forward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 2e4b6f6d8eaee..6c5104294208f 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -443,8 +443,88 @@ void main() { expect(pageController.page, isNotNull); expect(pageController.page, 1.0); }, - variant: TargetPlatformVariant.mobile(), - skip: kIsWeb, // https://github.com/flutter/flutter/issues/125582. + variant: const TargetPlatformVariant({ + TargetPlatform.android, + TargetPlatform.fuchsia, + }), + // [intended] Web does not support double tap + drag gestures on the tested platforms. + skip: kIsWeb, + ); + + testWidgets( + 'Vertical PageView beats SelectionArea child touch drag gestures on iOS', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/150897. + final PageController pageController = PageController(); + const String testValue = 'abc def ghi jkl mno pqr stu vwx yz'; + addTearDown(pageController.dispose); + + await tester.pumpWidget( + MaterialApp( + home: PageView( + scrollDirection: Axis.vertical, + controller: pageController, + children: [ + Center( + child: SelectableRegion( + selectionControls: materialTextSelectionControls, + child: const Text(testValue), + ), + ), + const SizedBox(height: 200.0, child: Center(child: Text('Page 2'))), + ], + ), + ), + ); + + final RenderParagraph paragraph = tester.renderObject( + find.descendant(of: find.text(testValue), matching: find.byType(RichText)), + ); + final Offset gPos = textOffsetToPosition(paragraph, testValue.indexOf('g')); + final Offset pPos = textOffsetToPosition(paragraph, testValue.indexOf('p')); + + // A double tap + drag should take precedence over parent drags. + final TestGesture gesture = await tester.startGesture(gPos); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await gesture.down(gPos); + await tester.pumpAndSettle(); + await gesture.moveTo(pPos); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph.selections, isNotEmpty); + expect( + paragraph.selections[0], + TextSelection( + baseOffset: testValue.indexOf('g'), + extentOffset: testValue.indexOf('p') + 3, + ), + ); + + expect(pageController.page, isNotNull); + expect(pageController.page, 0.0); + // A vertical drag directly on the SelectableRegion should move the page + // view to the next page. + final Rect selectableTextRect = tester.getRect(find.byType(SelectableRegion)); + // Simulate a pan by drag vertically first. + await gesture.down(selectableTextRect.center); + await tester.pump(); + await gesture.moveTo(selectableTextRect.center + const Offset(0.0, -200.0)); + // Introduce horizontal movement. + await gesture.moveTo(selectableTextRect.center + const Offset(5.0, -300.0)); + await gesture.moveTo(selectableTextRect.center + const Offset(-10.0, -400.0)); + // Continue dragging vertically. + await gesture.moveTo(selectableTextRect.center + const Offset(0.0, -500.0)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(pageController.page, isNotNull); + expect(pageController.page, 1.0); + }, + variant: TargetPlatformVariant.only(TargetPlatform.iOS), ); testWidgets('mouse single-click selection collapses the selection', ( @@ -6261,7 +6341,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('Copy'), findsNothing); }, - skip: !kIsWeb, // [intended] + skip: !kIsWeb, // [intended] This test verifies web behavior. ); }); diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 8e440a986e956..1c754e853144a 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -5582,8 +5582,9 @@ void main() { }); group('context menu', () { + // Regression test for https://github.com/flutter/flutter/issues/169001. testWidgets( - 'iOS uses the system context menu by default if supported', + 'iOS does not use the system context menu by default even when supported', (WidgetTester tester) async { tester.platformDispatcher.supportsShowingSystemContextMenu = true; addTearDown(() { @@ -5591,20 +5592,18 @@ void main() { tester.view.reset(); }); - final TextEditingController controller = TextEditingController(text: 'one two three'); - addTearDown(controller.dispose); await tester.pumpWidget( // Don't wrap with the global View so that the change to // platformDispatcher is read. wrapWithView: false, View( view: tester.view, - child: MaterialApp(home: Material(child: TextField(controller: controller))), + child: const MaterialApp(home: Material(child: SelectableText('one two three'))), ), ); // No context menu shown. - expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing); + expect(find.byType(CupertinoTextSelectionToolbar), findsNothing); expect(find.byType(SystemContextMenu), findsNothing); // Double tap to select the first word and show the menu. @@ -5613,8 +5612,8 @@ void main() { await tester.tapAt(textOffsetToPosition(tester, 1)); await tester.pump(SelectionOverlay.fadeDuration); - expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing); - expect(find.byType(SystemContextMenu), findsOneWidget); + expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget); + expect(find.byType(SystemContextMenu), findsNothing); }, skip: kIsWeb, // [intended] on web the browser handles the context menu. variant: TargetPlatformVariant.only(TargetPlatform.iOS), diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart index 6f526ea43a0d2..e782072b95379 100644 --- a/packages/flutter/test/widgets/semantics_tester.dart +++ b/packages/flutter/test/widgets/semantics_tester.dart @@ -48,8 +48,6 @@ class TestSemantics { this.textDirection, this.rect, this.transform, - this.elevation, - this.thickness, this.textSelection, this.children = const [], this.scrollIndex, @@ -100,8 +98,6 @@ class TestSemantics { assert(flags is int || flags is List), assert(actions is int || actions is List), rect = TestSemantics.rootRect, - elevation = 0.0, - thickness = 0.0, tags = tags?.toSet() ?? {}; /// Creates an object with some test semantics data, with the [id] and [rect] @@ -128,8 +124,6 @@ class TestSemantics { this.textDirection, this.rect, Matrix4? transform, - this.elevation, - this.thickness, this.textSelection, this.children = const [], this.scrollIndex, @@ -233,21 +227,6 @@ class TestSemantics { /// parent). final Matrix4? transform; - /// The elevation of this node relative to the parent node. - /// - /// See also: - /// - /// * [SemanticsConfiguration.elevation] for a detailed discussion regarding - /// elevation and semantics. - final double? elevation; - - /// The extend that this node occupies in z-direction starting at [elevation]. - /// - /// See also: - /// - /// * [SemanticsConfiguration.thickness] for a more detailed definition. - final double? thickness; - /// The index of the first visible semantic node within a scrollable. final int? scrollIndex; @@ -419,16 +398,6 @@ class TestSemantics { 'expected node id $id to have transform $transform but found transform:\n${nodeData.transform}.', ); } - if (elevation != null && elevation != nodeData.elevation) { - return fail( - 'expected node id $id to have elevation $elevation but found elevation:\n${nodeData.elevation}.', - ); - } - if (thickness != null && thickness != nodeData.thickness) { - return fail( - 'expected node id $id to have thickness $thickness but found thickness:\n${nodeData.thickness}.', - ); - } if (textSelection?.baseOffset != nodeData.textSelection?.baseOffset || textSelection?.extentOffset != nodeData.textSelection?.extentOffset) { return fail( @@ -583,12 +552,6 @@ class TestSemantics { '$indent transform:\n${transform.toString().trim().split('\n').map((String line) => '$indent $line').join('\n')},', ); } - if (elevation != null) { - buf.writeln('$indent elevation: $elevation,'); - } - if (thickness != null) { - buf.writeln('$indent thickness: $thickness,'); - } if (inputType != SemanticsInputType.none) { buf.writeln('$indent inputType: $inputType,'); } diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index 6b6525afb26e6..5dca52beaf4a2 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -879,47 +879,78 @@ void main() { expect(tester.getTopLeft(find.byKey(key)), Offset.zero); }); + // Regression test for https://github.com/flutter/flutter/issues/167801 testWidgets( - 'SliverMainAxisGroup scrolls to the correct position when focusing on a text field within a header', + 'Nesting SliverMainAxisGroups does not break ShowCaretOnScreen for text fields inside nested SliverMainAxisGroup', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); - addTearDown(controller.dispose); - final FocusNode textFieldFocus = FocusNode(); - addTearDown(textFieldFocus.dispose); - final FocusNode textFieldFocus2 = FocusNode(); - addTearDown(textFieldFocus2.dispose); - const ValueKey firstTextFieldKey = ValueKey(1); - - await tester.pumpWidget( - _buildSliverMainAxisGroup( - controller: controller, - slivers: [ - SliverPersistentHeader( - pinned: true, - delegate: _SliverTitleDelegate( - child: Container(color: Colors.red, height: 60.0), - height: 60.0, + // The number of groups and items per group needs to be high enough to reproduce the bug. + const int sliverGroupsCount = 3; + const int sliverGroupItemsCount = 60; + // To make working with the scroll offset easier, each item is a fixed height. + const double itemHeight = 72.0; + + final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); + + final Widget widget = MaterialApp( + theme: ThemeData( + inputDecorationTheme: const InputDecorationTheme( + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Color(0xFF1489FD))), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Color(0xFFB1BDC5))), + ), + ), + home: Scaffold( + body: CustomScrollView( + controller: scrollController, + slivers: [ + SliverMainAxisGroup( + slivers: [ + for (int i = 1; i <= sliverGroupsCount; i++) + SliverMainAxisGroup( + slivers: [ + SliverList.builder( + itemCount: sliverGroupItemsCount, + itemBuilder: (_, int index) { + final String label = 'Field $i.${index + 1}'; + + return SizedBox( + height: itemHeight, + child: Padding( + // This extra padding is to make visually debugging the test app a bit better, + // othwerwise the label text clips the text field above. + padding: const EdgeInsets.symmetric(vertical: 8), + child: TextField( + key: ValueKey(label), + decoration: InputDecoration(labelText: label), + ), + ), + ); + }, + ), + ], + ), + ], ), - ), - SliverToBoxAdapter( - child: Material(child: TextField(key: firstTextFieldKey, focusNode: textFieldFocus)), - ), - SliverToBoxAdapter(child: Container(color: Colors.green, height: 500)), - SliverToBoxAdapter(child: Material(child: TextField(focusNode: textFieldFocus2))), - ], + ], + ), ), ); - await tester.pumpAndSettle(); - await tester.pumpAndSettle(); + await tester.pumpWidget(widget); + + // Scroll down to the first field in the second group, so that it is at the top of the screen. + const double offset = sliverGroupItemsCount * itemHeight; + scrollController.jumpTo(offset); - textFieldFocus2.requestFocus(); await tester.pumpAndSettle(); - textFieldFocus.requestFocus(); + // Tap the field so that it gains focus and requests the scrollable to scroll it into view. + // However, since the field is at the top of the screen, far away from the keyboard, + // the scroll position should not change. + await tester.tap(find.byKey(const ValueKey('Field 2.1'))); await tester.pumpAndSettle(); - expect(tester.getTopLeft(find.byKey(firstTextFieldKey)), const Offset(0, 60)); + expect(scrollController.offset, offset); }, ); @@ -1118,22 +1149,3 @@ class TestDelegate extends SliverPersistentHeaderDelegate { @override bool shouldRebuild(TestDelegate oldDelegate) => true; } - -class _SliverTitleDelegate extends SliverPersistentHeaderDelegate { - _SliverTitleDelegate({required this.height, required this.child}); - final double height; - final Widget child; - - @override - double get minExtent => height; - @override - double get maxExtent => height; - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return child; - } - - @override - bool shouldRebuild(_SliverTitleDelegate oldDelegate) => true; -} 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 01218603b3062..052e884630661 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart @@ -97,11 +97,9 @@ void main() { TestSemantics( children: [ TestSemantics( - thickness: 0, children: [ TestSemantics( label: 'Hello', - elevation: 0, flags: [SemanticsFlag.isHeader, SemanticsFlag.namesRoute], textDirection: TextDirection.ltr, ), diff --git a/packages/flutter/test/widgets/system_context_menu_test.dart b/packages/flutter/test/widgets/system_context_menu_test.dart index 9cd53a9f4e205..7ebadd0d686ae 100644 --- a/packages/flutter/test/widgets/system_context_menu_test.dart +++ b/packages/flutter/test/widgets/system_context_menu_test.dart @@ -698,4 +698,34 @@ void main() { ); }, ); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemLookUp debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemLookUp item = IOSSystemContextMenuItemLookUp(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemSearchWeb debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemSearchWeb item = IOSSystemContextMenuItemSearchWeb(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemShare debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemShare item = IOSSystemContextMenuItemShare(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); } diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 41588d1e5f54c..0006f74f45d07 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -996,11 +996,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ); testWidgets( - 'WidgetInspector Move Exit Selection Mode button to the right / left', + '[LTR] WidgetInspector Move Exit Selection Mode button to the right then left', (WidgetTester tester) async { - // Enable widget selection mode. WidgetInspectorService.instance.isSelectMode = true; - final GlobalKey inspectorKey = GlobalKey(); setupDefaultPubRootDirectory(service); @@ -1023,12 +1021,12 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { BuildContext context, { required VoidCallback onPressed, required String semanticsLabel, - bool isLeftAligned = true, + bool usesDefaultAlignment = true, }) { return Material( child: ElevatedButton( onPressed: onPressed, - child: Text(isLeftAligned ? 'MOVE RIGHT' : 'MOVE LEFT'), + child: Text(usesDefaultAlignment ? 'MOVE RIGHT' : 'MOVE LEFT'), ), ); } @@ -1050,33 +1048,104 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ), ); - // Initially the exit select button is on the left. final Finder exitButton = buttonFinder('EXIT SELECT MODE'); expect(exitButton, findsOneWidget); final Finder moveRightButton = buttonFinder('MOVE RIGHT'); expect(moveRightButton, findsOneWidget); final double initialExitButtonX = tester.getCenter(exitButton).dx; - // Move the button to the right. await tester.tap(moveRightButton); await tester.pump(); - // Verify the button is now on the right. - expect(moveRightButton, findsNothing); final Finder moveLeftButton = buttonFinder('MOVE LEFT'); expect(moveLeftButton, findsOneWidget); - final double exitButtonXAfterMovingRight = tester.getCenter(exitButton).dx; - expect(initialExitButtonX, lessThan(exitButtonXAfterMovingRight)); + final double movedExitButtonX = tester.getCenter(exitButton).dx; + + expect(initialExitButtonX, lessThan(movedExitButtonX), reason: 'LTR: should move right'); - // Move the button to the left again. await tester.tap(moveLeftButton); await tester.pump(); - // Verify the button is in its original position. - expect(moveLeftButton, findsNothing); + final double finalExitButtonX = tester.getCenter(exitButton).dx; + expect(finalExitButtonX, equals(initialExitButtonX)); + }, + // [intended] Test requires --track-widget-creation flag. + skip: !WidgetInspectorService.instance.isWidgetCreationTracked(), + ); + + testWidgets( + '[RTL] WidgetInspector Move Exit Selection Mode button to the left then right', + (WidgetTester tester) async { + WidgetInspectorService.instance.isSelectMode = true; + final GlobalKey inspectorKey = GlobalKey(); + setupDefaultPubRootDirectory(service); + + Widget exitWidgetSelectionButtonBuilder( + BuildContext context, { + required VoidCallback onPressed, + required String semanticsLabel, + required GlobalKey key, + }) { + return Material( + child: ElevatedButton( + onPressed: onPressed, + key: key, + child: const Text('EXIT SELECT MODE'), + ), + ); + } + + Widget moveWidgetSelectionButtonBuilder( + BuildContext context, { + required VoidCallback onPressed, + required String semanticsLabel, + bool usesDefaultAlignment = true, + }) { + return Material( + child: ElevatedButton( + onPressed: onPressed, + child: Text(usesDefaultAlignment ? 'MOVE RIGHT' : 'MOVE LEFT'), + ), + ); + } + + Finder buttonFinder(String buttonText) { + return find.ancestor(of: find.text(buttonText), matching: find.byType(ElevatedButton)); + } + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.rtl, + child: WidgetInspector( + key: inspectorKey, + exitWidgetSelectionButtonBuilder: exitWidgetSelectionButtonBuilder, + moveExitWidgetSelectionButtonBuilder: moveWidgetSelectionButtonBuilder, + tapBehaviorButtonBuilder: null, + child: const Text('APP'), + ), + ), + ); + + final Finder exitButton = buttonFinder('EXIT SELECT MODE'); + expect(exitButton, findsOneWidget); + final Finder moveRightButton = buttonFinder('MOVE RIGHT'); expect(moveRightButton, findsOneWidget); - final double exitButtonXAfterMovingLeft = tester.getCenter(exitButton).dx; - expect(exitButtonXAfterMovingLeft, equals(initialExitButtonX)); + final double initialExitButtonX = tester.getCenter(exitButton).dx; + + await tester.tap(moveRightButton); + await tester.pump(); + + final Finder moveLeftButton = buttonFinder('MOVE LEFT'); + expect(moveLeftButton, findsOneWidget); + final double movedExitButtonX = tester.getCenter(exitButton).dx; + + expect(initialExitButtonX, greaterThan(movedExitButtonX), reason: 'RTL: should move left'); + + await tester.tap(moveLeftButton); + await tester.pump(); + + final double finalExitButtonX = tester.getCenter(exitButton).dx; + expect(finalExitButtonX, equals(initialExitButtonX)); }, // [intended] Test requires --track-widget-creation flag. skip: !WidgetInspectorService.instance.isWidgetCreationTracked(), diff --git a/packages/flutter/test_private/bin/test_private.dart b/packages/flutter/test_private/bin/test_private.dart index a6a7c03ef842f..bc3a41a4804e2 100644 --- a/packages/flutter/test_private/bin/test_private.dart +++ b/packages/flutter/test_private/bin/test_private.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:path/path.dart' as path; import 'package:process_runner/process_runner.dart'; @@ -196,10 +197,16 @@ class TestCase { } // Copy the pubspec to the right place. - makeAbsolute( - pubspec, - workingDirectory: privateTestsDir, - ).copySync(path.join(tmpdir.absolute.path, 'pubspec.yaml')); + final String pubspecPath = path.join(tmpdir.absolute.path, 'pubspec.yaml'); + makeAbsolute(pubspec, workingDirectory: privateTestsDir).copySync(pubspecPath); + + final File pubspecCopy = File(pubspecPath); + pubspecCopy.writeAsStringSync( + pubspecCopy + .readAsLinesSync() + .whereNot((String line) => line.startsWith('resolution: workspace')) + .join('\n'), + ); // Use Flutter's analysis_options.yaml file from packages/flutter. File(path.join(tmpdir.absolute.path, 'analysis_options.yaml')).writeAsStringSync( diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 604bf5f77855f..ba98ef7fa550f 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -4,20 +4,16 @@ description: Tests private interfaces of the flutter environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # # For detailed instructions, refer to: # https://github.com/flutter/flutter/blob/main/docs/infra/Updating-dependencies-in-Flutter.md - meta: 1.16.0 - path: 1.9.1 - process: 5.0.3 - process_runner: 4.2.0 + path: any + process_runner: any - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: any -# PUBSPEC CHECKSUM: 5bc0 +# PUBSPEC CHECKSUM: 8lddt7 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 78e2f7e2a17f7..645bad897d18d 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -3,6 +3,8 @@ name: animated_icons_private_test environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # @@ -14,37 +16,11 @@ dependencies: sdk: flutter sky_engine: sdk: flutter - characters: 1.4.0 - collection: 1.19.1 - meta: 1.16.0 - vector_math: 2.1.4 - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: sdk: flutter - fake_async: 1.3.3 - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bba6 +# PUBSPEC CHECKSUM: k2cen3 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index aa4900a9f04a4..9275a57e9189f 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -5,76 +5,26 @@ homepage: https://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - file: 7.0.1 + file: any flutter: sdk: flutter flutter_test: sdk: flutter fuchsia_remote_debug_protocol: sdk: flutter - path: 1.9.1 - meta: 1.16.0 - vm_service: 15.0.0 - webdriver: 3.1.0 + path: any + meta: any + vm_service: any + webdriver: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: any dev_dependencies: - fake_async: 1.3.3 - test: 1.26.1 + fake_async: any + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c572 +# PUBSPEC CHECKSUM: r4u6gv diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index 778d64680f807..bd96fe0bc40cf 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -3,6 +3,8 @@ name: flutter_goldens environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # @@ -12,32 +14,11 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - crypto: 3.0.6 - file: 7.0.1 - meta: 1.16.0 - platform: 3.1.6 - process: 5.0.3 + crypto: any + file: any + platform: any + process: any - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any -# PUBSPEC CHECKSUM: bba6 +# PUBSPEC CHECKSUM: 563qhd diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index df748cd70e32d..4cc48c90b408a 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -3,6 +3,8 @@ name: flutter_localizations environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # @@ -12,32 +14,10 @@ dependencies: flutter: sdk: flutter intl: 0.20.2 - - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.9.1 dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 887b +# PUBSPEC CHECKSUM: c2j4ng diff --git a/packages/flutter_test/lib/src/_goldens_io.dart b/packages/flutter_test/lib/src/_goldens_io.dart index 8fe478c8366b9..e99f293e89125 100644 --- a/packages/flutter_test/lib/src/_goldens_io.dart +++ b/packages/flutter_test/lib/src/_goldens_io.dart @@ -285,42 +285,6 @@ ByteData _invert(ByteData imageBytes) { return bytes; } -/// An unsupported [WebGoldenComparator] that exists for API compatibility. -@Deprecated( - 'Use GoldenFileComparator instead. ' - 'This feature was deprecated after v3.28.0-0.1.pre.', -) -class DefaultWebGoldenComparator extends WebGoldenComparator { - /// This is provided to prevent warnings from the analyzer. - @Deprecated( - 'Use a GoldenFileComparator implementation instead. ' - 'This feature was deprecated after v3.28.0-0.1.pre.', - ) - DefaultWebGoldenComparator(Uri _) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } - - @override - Future compare(double width, double height, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } - - @override - Future update(double width, double height, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } - - @override - Future compareBytes(Uint8List bytes, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } -} - /// Reads the red value out of a 32 bit rgba pixel. int _readRed(int pixel) => (pixel >> 24) & 0xff; diff --git a/packages/flutter_test/lib/src/_goldens_web.dart b/packages/flutter_test/lib/src/_goldens_web.dart index 8895e68a3aea1..029d40fa7a314 100644 --- a/packages/flutter_test/lib/src/_goldens_web.dart +++ b/packages/flutter_test/lib/src/_goldens_web.dart @@ -76,74 +76,3 @@ final class HttpProxyGoldenComparator extends GoldenFileComparator { await compare(bytes, golden); } } - -/// The default [WebGoldenComparator] implementation for `flutter test`. -/// -/// This comparator will send a request to the test server for golden comparison -/// which will then defer the comparison to [goldenFileComparator]. -/// -/// See also: -/// -/// * [matchesGoldenFile], the function that invokes the comparator. -@Deprecated( - 'Use goldenFileComparator instead. ' - 'This feature was deprecated after v3.28.0-0.1.pre.', -) -class DefaultWebGoldenComparator extends WebGoldenComparator { - /// Creates a new [DefaultWebGoldenComparator] for the specified [testUri]. - /// - /// Golden file keys will be interpreted as file paths relative to the - /// directory in which [testUri] resides. - /// - /// The [testUri] must represent a file. - @Deprecated( - 'Use an implementation of GoldenFileComparator instead. ' - 'This feature was deprecated after v3.28.0-0.1.pre.', - ) - DefaultWebGoldenComparator(Uri testUri) : _comparatorImpl = HttpProxyGoldenComparator(testUri); - - // TODO(matanlurey): Refactor as part of https://github.com/flutter/flutter/issues/160261. - final HttpProxyGoldenComparator _comparatorImpl; - - @override - Future compare(double width, double height, Uri golden) async { - final String key = golden.toString(); - final web.Response response = - await web.window - .fetch( - 'flutter_goldens'.toJS, - web.RequestInit( - method: 'POST', - body: - json.encode({ - 'testUri': _comparatorImpl._testUri.toString(), - 'key': key, - 'width': width.round(), - 'height': height.round(), - }).toJS, - ), - ) - .toDart; - final String responseText = (await response.text().toDart).toDart; - if (responseText == 'true') { - return true; - } - fail(responseText); - } - - @override - Future update(double width, double height, Uri golden) async { - // Update is handled on the server side, just use the same logic here - await compare(width, height, golden); - } - - @override - Future compareBytes(Uint8List bytes, Uri golden) async { - return _comparatorImpl.compare(bytes, golden); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) async { - await _comparatorImpl.update(golden, bytes); - } -} diff --git a/packages/flutter_test/lib/src/goldens.dart b/packages/flutter_test/lib/src/goldens.dart index 6e66f92f87aeb..0a2bb94ca842f 100644 --- a/packages/flutter_test/lib/src/goldens.dart +++ b/packages/flutter_test/lib/src/goldens.dart @@ -195,142 +195,6 @@ abstract class GoldenFileComparator { /// directory-level. GoldenFileComparator goldenFileComparator = const TrivialComparator._(); -/// Compares image pixels against a golden image file. -/// -/// Instances of this comparator will be used as the backend for -/// [matchesGoldenFile] when tests are running on Flutter Web, and will usually -/// implemented by deferring the screenshot taking and image comparison to a -/// test server. -/// -/// Instances of this comparator will be invoked by the test framework in the -/// [TestWidgetsFlutterBinding.runAsync] zone and are thus not subject to the -/// fake async constraints that are normally imposed on widget tests (i.e. the -/// need or the ability to call [WidgetTester.pump] to advance the microtask -/// queue). Prior to the invocation, the test framework will render only the -/// [Element] to be compared on the screen. -/// -/// See also: -/// -/// * [GoldenFileComparator] for the comparator to be used when the test is -/// not running in a web browser. -/// * [DefaultWebGoldenComparator] for the default [WebGoldenComparator] -/// implementation for `flutter test`. -/// * [matchesGoldenFile], the function that invokes the comparator. -@Deprecated( - 'Use GoldenFileComparator instead. ' - 'This feature was deprecated after v3.28.0-0.1.pre.', -) -abstract class WebGoldenComparator { - /// Compares the rendered pixels of size [width]x[height] that is being - /// rendered on the top left of the screen against the golden file identified - /// by [golden]. - /// - /// The returned future completes with a boolean value that indicates whether - /// the pixels rendered on screen match the golden file's pixels. - /// - /// In the case of comparison mismatch, the comparator may choose to throw a - /// [TestFailure] if it wants to control the failure message, often in the - /// form of a [ComparisonResult] that provides detailed information about the - /// mismatch. - /// - /// The method by which [golden] is located and by which its bytes are loaded - /// is left up to the implementation class. For instance, some implementations - /// may load files from the local file system, whereas others may load files - /// over the network or from a remote repository. - Future compare(double width, double height, Uri golden); - - /// Updates the golden file identified by [golden] with rendered pixels of - /// [width]x[height]. - /// - /// This will be invoked in lieu of [compare] when [autoUpdateGoldenFiles] - /// is `true` (which gets set automatically by the test framework when the - /// user runs `flutter test --update-goldens --platform=chrome`). - /// - /// The method by which [golden] is located and by which its bytes are written - /// is left up to the implementation class. - Future update(double width, double height, Uri golden); - - /// Compares the pixels of decoded png [bytes] against the golden file - /// identified by [golden]. - /// - /// The returned future completes with a boolean value that indicates whether - /// the pixels rendered on screen match the golden file's pixels. - /// - /// In the case of comparison mismatch, the comparator may choose to throw a - /// [TestFailure] if it wants to control the failure message, often in the - /// form of a [ComparisonResult] that provides detailed information about the - /// mismatch. - /// - /// The method by which [golden] is located and by which its bytes are loaded - /// is left up to the implementation class. For instance, some implementations - /// may load files from the local file system, whereas others may load files - /// over the network or from a remote repository. - Future compareBytes(Uint8List bytes, Uri golden); - - /// Compares the pixels of decoded png [bytes] against the golden file - /// identified by [golden]. - /// - /// This will be invoked in lieu of [compareBytes] when [autoUpdateGoldenFiles] - /// is `true` (which gets set automatically by the test framework when the - /// user runs `flutter test --update-goldens --platform=chrome`). - /// - /// The method by which [golden] is located and by which its bytes are written - /// is left up to the implementation class. - Future updateBytes(Uint8List bytes, Uri golden); - - /// Returns a new golden file [Uri] to incorporate any [version] number with - /// the [key]. - /// - /// The [version] is an optional int that can be used to differentiate - /// historical golden files. - /// - /// Version numbers are used in golden file tests for package:flutter. You can - /// learn more about these tests [here](https://github.com/flutter/flutter/blob/main/docs/contributing/testing/Writing-a-golden-file-test-for-package-flutter.md). - Uri getTestUri(Uri key, int? version) { - if (version == null) { - return key; - } - final String keyString = key.toString(); - final String extension = path.extension(keyString); - return Uri.parse('${keyString.split(extension).join()}.$version$extension'); - } -} - -/// Compares pixels against those of a golden image file. -/// -/// This comparator is used as the backend for [matchesGoldenFile] when tests -/// are running in a web browser. -/// -/// When using `flutter test --platform=chrome`, a comparator implemented by -/// [DefaultWebGoldenComparator] is used if no other comparator is specified. It -/// will send a request to the test server, which uses [goldenFileComparator] -/// for golden file comparison. -/// -/// When using `flutter test --update-goldens`, the [DefaultWebGoldenComparator] -/// updates the files on disk to match the rendering. -/// -/// When using `flutter run`, the default comparator -/// (`_TrivialWebGoldenComparator`) is used. It prints a message to the console -/// but otherwise does nothing. This allows tests to be developed visually on a -/// web browser. -/// -/// Callers may choose to override the default comparator by setting this to a -/// custom comparator during test set-up (or using directory-level test -/// configuration). For example, some projects may wish to install a comparator -/// with tolerance levels for allowable differences. -/// -/// See also: -/// -/// * [flutter_test] for more information about how to configure tests at the -/// directory-level. -/// * [goldenFileComparator], the comparator used when tests are not running on -/// a web browser. -WebGoldenComparator get webGoldenComparator => _webGoldenComparator; -WebGoldenComparator _webGoldenComparator = const _TrivialWebGoldenComparator._(); -set webGoldenComparator(WebGoldenComparator value) { - _webGoldenComparator = value; -} - /// Whether golden files should be automatically updated during tests rather /// than compared to the image bytes recorded by the tests. /// @@ -386,44 +250,6 @@ class TrivialComparator implements GoldenFileComparator { } } -class _TrivialWebGoldenComparator implements WebGoldenComparator { - const _TrivialWebGoldenComparator._(); - - @override - Future compare(double width, double height, Uri golden) { - return _warnAboutSkipping(golden); - } - - @override - Future update(double width, double height, Uri golden) { - throw StateError('webGoldenComparator has not been initialized'); - } - - @override - Uri getTestUri(Uri key, int? version) { - return key; - } - - @override - Future compareBytes(Uint8List bytes, Uri golden) { - return _warnAboutSkipping(golden); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) { - throw StateError('webGoldenComparator has not been initialized'); - } - - Future _warnAboutSkipping(Uri golden) { - // Ideally we would use markTestSkipped here but in some situations, - // comparators are called outside of tests. - // See also: https://github.com/flutter/flutter/issues/91285 - // ignore: avoid_print - print('Golden comparison requested for "$golden"; skipping...'); - return Future.value(true); - } -} - /// The result of a pixel comparison test. /// /// The [ComparisonResult] will always indicate if a test has [passed]. The diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index e1079c816cab4..a6ca25b3d082d 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -762,8 +762,6 @@ Matcher matchesSemantics({ textDirection: textDirection, rect: rect, size: size, - elevation: elevation, - thickness: thickness, platformViewId: platformViewId, customActions: customActions, maxValueLength: maxValueLength, @@ -960,8 +958,6 @@ Matcher containsSemantics({ textDirection: textDirection, rect: rect, size: size, - elevation: elevation, - thickness: thickness, platformViewId: platformViewId, customActions: customActions, maxValueLength: maxValueLength, @@ -2392,8 +2388,6 @@ class _MatchesSemanticsData extends Matcher { required this.textDirection, required this.rect, required this.size, - required this.elevation, - required this.thickness, required this.platformViewId, required this.maxValueLength, required this.currentValueLength, @@ -2547,8 +2541,6 @@ class _MatchesSemanticsData extends Matcher { final TextDirection? textDirection; final Rect? rect; final Size? size; - final double? elevation; - final double? thickness; final int? platformViewId; final int? maxValueLength; final int? currentValueLength; @@ -2650,12 +2642,6 @@ class _MatchesSemanticsData extends Matcher { if (size != null) { description.add(' with size: $size'); } - if (elevation != null) { - description.add(' with elevation: $elevation'); - } - if (thickness != null) { - description.add(' with thickness: $thickness'); - } if (platformViewId != null) { description.add(' with platformViewId: $platformViewId'); } @@ -2795,12 +2781,6 @@ class _MatchesSemanticsData extends Matcher { if (size != null && size != data.rect.size) { return failWithDescription(matchState, 'size was: ${data.rect.size}'); } - if (elevation != null && elevation != data.elevation) { - return failWithDescription(matchState, 'elevation was: ${data.elevation}'); - } - if (thickness != null && thickness != data.thickness) { - return failWithDescription(matchState, 'thickness was: ${data.thickness}'); - } if (platformViewId != null && platformViewId != data.platformViewId) { return failWithDescription(matchState, 'platformViewId was: ${data.platformViewId}'); } diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index 562cd1bcbe04f..f2eb6f8a0468e 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -32,6 +32,7 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { this.reduceMotion = false, this.highContrast = false, this.onOffSwitchLabels = false, + this.announce = false, }); /// An instance of [AccessibilityFeatures] where all the features are enabled. @@ -43,6 +44,7 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { reduceMotion: true, highContrast: true, onOffSwitchLabels: true, + announce: true, ); @override @@ -66,6 +68,9 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { @override final bool onOffSwitchLabels; + @override + final bool announce; + @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) { @@ -78,7 +83,8 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { other.boldText == boldText && other.reduceMotion == reduceMotion && other.highContrast == highContrast && - other.onOffSwitchLabels == onOffSwitchLabels; + other.onOffSwitchLabels == onOffSwitchLabels && + other.announce == announce; } @override @@ -91,6 +97,7 @@ class FakeAccessibilityFeatures implements AccessibilityFeatures { reduceMotion, highContrast, onOffSwitchLabels, + announce, ); } diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index fdd20a4cd2604..c0dc4f24c16e8 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -3,6 +3,8 @@ name: flutter_test environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". # @@ -31,31 +33,18 @@ dependencies: stack_trace: 1.12.1 # Used by globalToLocal et al. - vector_math: 2.1.4 + vector_math: 2.2.0 # Used to detect memory leaks with `testWidgets`. leak_tracker_flutter_testing: 3.0.10 - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.19.1 + meta: 1.16.0 + stream_channel: 2.1.4 dev_dependencies: - file: 7.0.1 + file: any flutter_driver: sdk: flutter - sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 597c +# PUBSPEC CHECKSUM: 9ghr diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index 56b9a6ae09dc9..d337b3fcda688 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -746,8 +746,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1048,8 +1046,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1150,8 +1146,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1256,8 +1250,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1289,8 +1281,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1379,8 +1369,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, diff --git a/packages/flutter_test/test/test_config/project_root/pubspec.yaml b/packages/flutter_test/test/test_config/project_root/pubspec.yaml index e5d81182ba09c..e9abdcaf7a830 100644 --- a/packages/flutter_test/test/test_config/project_root/pubspec.yaml +++ b/packages/flutter_test/test/test_config/project_root/pubspec.yaml @@ -6,4 +6,4 @@ name: dummy environment: sdk: ^3.7.0-0 -# PUBSPEC CHECKSUM: 0000 +# PUBSPEC CHECKSUM: 1 diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index f2ef7eeb9f508..72f69d15f763f 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -128,6 +128,15 @@ class Context { } errorOutput.write(resultStderr); echoError(errorOutput.toString()); + + // Stream stderr to the Flutter build process. + // When in verbose mode, `echoError` above will show the logs. So only + // stream if not in verbose mode to avoid duplicate logs. + // Also, only stream if exitCode is 0 since errors are handled separately + // by the tool on failure. + if (!verbose && exitCode == 0) { + streamOutput(errorOutput.toString()); + } } if (!allowFail && result.exitCode != 0) { throw Exception('Command "$bin ${args.join(' ')}" exited with code ${result.exitCode}'); @@ -506,6 +515,8 @@ class Context { final String buildMode = parseFlutterBuildMode(); + _validateBuildMode(platform, buildMode); + final List flutterArgs = _generateFlutterArgsForAssemble( command: 'build', buildMode: buildMode, @@ -534,6 +545,53 @@ class Context { echo('Project $projectPath built and packaged successfully.'); } + /// Validate that the build mode targeted matches the build mode set by the + /// Flutter CLI. + /// If it doesn't match, print a warning unless the Xcode action is `install`, + /// which means the app is being archived for distribution. In that case, print + /// an error and fail the build. + /// + /// The targeted build mode might not match the one set by Flutter CLI when it + /// is changed and ran directly through Xcode. + /// + /// Flutter may change settings or files depending on the build mode. For + /// example, dev dependencies are excluded from release builds and requires + /// the Flutter CLI to update certain files. + void _validateBuildMode(TargetPlatform platform, String currentBuildMode) { + final String? buildModeCLILastUsed = environment['FLUTTER_CLI_BUILD_MODE']; + + // Also fail the build if ACTION=install, which indicates the app is being + // built for distribution. + final String? action = environment['ACTION']; + final bool fatal = action == 'install'; + + if (buildModeCLILastUsed == null) { + final String message = + 'Your Flutter build settings are outdated. Please run ' + '"flutter build ${platform.name} --config-only --$currentBuildMode" in your Flutter ' + 'project and try again.\n'; + if (fatal) { + echoXcodeError(message); + exitApp(-1); + } else { + echoXcodeWarning(message); + return; + } + } + if (currentBuildMode != buildModeCLILastUsed) { + final String message = + 'Your Flutter project is currently configured for $buildModeCLILastUsed mode. ' + 'Please run `flutter build ${platform.name} --config-only --$currentBuildMode` ' + 'in your Flutter project to update your settings.\n'; + if (fatal) { + echoXcodeError(message); + exitApp(-1); + } else { + echoXcodeWarning(message); + } + } + } + List _generateFlutterArgsForAssemble({ required String command, required String buildMode, @@ -626,7 +684,6 @@ class Context { '--DartDefines=${environment['DART_DEFINES'] ?? ''}', '--ExtraFrontEndOptions=${environment['EXTRA_FRONT_END_OPTIONS'] ?? ''}', '-dSrcRoot=${environment['SRCROOT'] ?? ''}', - '-dDevDependenciesEnabled=${environment['FLUTTER_DEV_DEPENDENCIES_ENABLED'] ?? ''}', ]); if (platform == TargetPlatform.ios) { diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt index 60c724ffcc4c9..9f5a9f32a8a10 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt @@ -20,6 +20,7 @@ import org.gradle.api.Task import org.gradle.api.UnknownTaskException import org.gradle.api.file.Directory import org.gradle.api.tasks.Copy +import org.gradle.api.tasks.TaskInstantiationException import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Jar import org.gradle.internal.os.OperatingSystem @@ -97,6 +98,13 @@ class FlutterPlugin : Plugin { repositories.maven { url = uri(repository!!) } + if (plugins.hasPlugin("com.android.application") && isInvokedFromAndroidStudio()) { + dependencies.add("compileOnly", "io.flutter:flutter_embedding_debug:$engineVersion") + dependencies.add("compileOnly", "io.flutter:armeabi_v7a_debug:$engineVersion") + dependencies.add("compileOnly", "io.flutter:arm64_v8a_debug:$engineVersion") + dependencies.add("compileOnly", "io.flutter:x86_debug:$engineVersion") + dependencies.add("compileOnly", "io.flutter:x86_64_debug:$engineVersion") + } } project.apply { @@ -292,19 +300,23 @@ class FlutterPlugin : Plugin { } private fun addTaskForLockfileGeneration(rootProject: Project) { - rootProject.tasks.register("generateLockfiles") { - doLast { - rootProject.subprojects.forEach { subproject -> - val gradlew: String = - getExecutableNameForPlatform("${rootProject.projectDir}/gradlew") - val execOps = rootProject.serviceOf() - execOps.exec { - workingDir(rootProject.projectDir) - executable(gradlew) - args(":${subproject.name}:dependencies", "--write-locks") + try { + rootProject.tasks.register("generateLockfiles") { + doLast { + rootProject.subprojects.forEach { subproject -> + val gradlew: String = + getExecutableNameForPlatform("${rootProject.projectDir}/gradlew") + val execOps = rootProject.serviceOf() + execOps.exec { + workingDir(rootProject.projectDir) + executable(gradlew) + args(":${subproject.name}:dependencies", "--write-locks") + } } } } + } catch (e: TaskInstantiationException) { + // ignored } } @@ -773,4 +785,12 @@ class FlutterPlugin : Plugin { return copyFlutterAssetsTask } } + + /** + * Returns true if the Gradle task is invoked by Android Studio. + * + * This is true when the property `android.injected.invoked.from.ide` is passed to Gradle. + * This property is set by Android Studio when it invokes a Gradle task. + */ + private fun isInvokedFromAndroidStudio(): Boolean = project?.hasProperty("android.injected.invoked.from.ide") == true } diff --git a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt index 72ac88b0a2df9..a1fecf24ec5c7 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt @@ -4,7 +4,6 @@ package com.flutter.gradle.plugins -import androidx.annotation.VisibleForTesting import com.android.builder.model.BuildType import com.flutter.gradle.FlutterExtension import com.flutter.gradle.FlutterPluginUtils @@ -103,13 +102,6 @@ class PluginHandler( */ private const val WEBSITE_DEPLOYMENT_ANDROID_BUILD_CONFIG = "https://flutter.dev/to/review-gradle-config" - @VisibleForTesting internal val legacyFlutterPluginsWarning = - """ - Warning: This project is still reading the deprecated '.flutter-plugins. file. - In an upcoming stable release support for this file will be completely removed and your build will fail. - See https:/flutter.dev/to/flutter-plugins-configuration. - """.trimIndent() - /** * Performs configuration related to the plugin's Gradle [Project], including * 1. Adding the plugin itself as a dependency to the main project. diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index d02cc70bce356..ad09d7064ae6f 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -276,7 +276,7 @@ List generateCommands({required bool verboseHelp, required bool SymbolizeCommand(stdio: globals.stdio, fileSystem: globals.fs), // Development-only commands. These are always hidden, IdeConfigCommand(), - UpdatePackagesCommand(), + UpdatePackagesCommand(verboseHelp: verboseHelp), ]; /// An abstraction for instantiation of the correct logger type. diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index 2165de70cfc2e..d24c23018c3d8 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -207,8 +207,6 @@ class AndroidDevice extends Device { } case 'x86_64': return TargetPlatform.android_x64; - case 'x86': - return TargetPlatform.android_x86; default: return TargetPlatform.android_arm; } @@ -221,8 +219,6 @@ class AndroidDevice extends Device { case TargetPlatform.android_arm64: case TargetPlatform.android_x64: return buildMode != BuildMode.jitRelease; - case TargetPlatform.android_x86: - return buildMode == BuildMode.debug; case TargetPlatform.android: case TargetPlatform.darwin: case TargetPlatform.fuchsia_arm64: @@ -535,10 +531,6 @@ class AndroidDevice extends Device { } final TargetPlatform devicePlatform = await targetPlatform; - if (devicePlatform == TargetPlatform.android_x86 && !debuggingOptions.buildInfo.isDebug) { - _logger.printError('Profile and release builds are only supported on ARM/x64 targets.'); - return LaunchResult.failed(); - } AndroidApk? builtPackage = package; AndroidArch androidArch; @@ -549,8 +541,6 @@ class AndroidDevice extends Device { androidArch = AndroidArch.arm64_v8a; case TargetPlatform.android_x64: androidArch = AndroidArch.x86_64; - case TargetPlatform.android_x86: - androidArch = AndroidArch.x86; case TargetPlatform.android: case TargetPlatform.darwin: case TargetPlatform.fuchsia_arm64: diff --git a/packages/flutter_tools/lib/src/android/build_validation.dart b/packages/flutter_tools/lib/src/android/build_validation.dart index 5a88aae980452..cad61ca627bf7 100644 --- a/packages/flutter_tools/lib/src/android/build_validation.dart +++ b/packages/flutter_tools/lib/src/android/build_validation.dart @@ -18,12 +18,6 @@ void validateBuild(AndroidBuildInfo androidBuildInfo) { '--target-platform flag.', ); } - if (buildInfo.mode.isPrecompiled && androidBuildInfo.targetArchs.contains(AndroidArch.x86)) { - throwToolExit( - 'Cannot build ${androidBuildInfo.buildInfo.mode.cliName} mode for x86 ABI.\n' - 'For more information see $kSupportedAbis .', - ); - } if (buildInfo.buildNumber != null) { final int? result = int.tryParse(buildInfo.buildNumber!); if (result == null) { diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index d586bfa02ee29..27150d08461a0 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -204,11 +204,6 @@ class AndroidGradleBuilder implements AndroidBuilder { outputDirectory = outputDirectory.childDirectory('host'); } - final bool containsX86Targets = - androidBuildInfo.where((AndroidBuildInfo info) => info.containsX86Target).isNotEmpty; - if (containsX86Targets) { - _logger.printWarning(androidX86DeprecationWarning); - } for (final AndroidBuildInfo androidBuildInfo in androidBuildInfo) { await generateTooling(project, releaseMode: androidBuildInfo.buildInfo.isRelease); await buildGradleAar( @@ -454,9 +449,6 @@ class AndroidGradleBuilder implements AndroidBuilder { int retry = 0, @visibleForTesting int? maxRetries, }) async { - if (androidBuildInfo.containsX86Target) { - _logger.printWarning(androidX86DeprecationWarning); - } if (!project.android.isSupportedVersion) { _exitWithUnsupportedProjectMessage(_logger.terminal, _analytics); } @@ -723,14 +715,15 @@ class AndroidGradleBuilder implements AndroidBuilder { return false; } - // As long as libflutter.so.sym is present for at least one architecture, + // As long as libflutter.so.sym or libflutter.so.dbg is present for at least one architecture, // assume AGP succeeded in stripping. - if (result.stdout.contains('libflutter.so.sym')) { + if (result.stdout.contains('libflutter.so.sym') || + result.stdout.contains('libflutter.so.dbg')) { return true; } _logger.printTrace( - 'libflutter.so.sym not present when checking final appbundle for debug symbols.', + 'libflutter.so.sym or libflutter.so.dbg not present when checking final appbundle for debug symbols.', ); return false; } @@ -1354,9 +1347,7 @@ Directory _getLocalEngineRepo({ String _getAbiByLocalEnginePath(String engineOutPath) { String result = 'armeabi_v7a'; - if (engineOutPath.contains('x86')) { - result = 'x86'; - } else if (engineOutPath.contains('x64')) { + if (engineOutPath.contains('x64')) { result = 'x86_64'; } else if (engineOutPath.contains('arm64')) { result = 'arm64_v8a'; @@ -1366,9 +1357,7 @@ String _getAbiByLocalEnginePath(String engineOutPath) { String _getTargetPlatformByLocalEnginePath(String engineOutPath) { String result = 'android-arm'; - if (engineOutPath.contains('x86')) { - result = 'android-x86'; - } else if (engineOutPath.contains('x64')) { + if (engineOutPath.contains('x64')) { result = 'android-x64'; } else if (engineOutPath.contains('arm64')) { result = 'android-arm64'; diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index ce364d9510091..24ef98cadd00d 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -164,7 +164,6 @@ TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case null: return targetPlatform; } @@ -488,7 +487,7 @@ class CachedArtifacts implements Artifacts { return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName); case HostArtifact.iproxy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); - return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); + return _cache.getArtifactDirectory('libusbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); @@ -511,7 +510,6 @@ class CachedArtifacts implements Artifacts { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: assert(platform != TargetPlatform.android); return _getAndroidArtifactPath(artifact, platform!, mode!); case TargetPlatform.ios: @@ -897,7 +895,6 @@ class CachedArtifacts implements Artifacts { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: assert(mode != null, 'Need to specify a build mode for platform $platform.'); final String suffix = mode != BuildMode.debug ? '-${kebabCase(mode!.cliName)}' : ''; return _fileSystem.path.join(engineDir, platformName + suffix); @@ -1165,7 +1162,7 @@ class CachedLocalEngineArtifacts implements Artifacts { return _cache.getArtifactDirectory('ios-deploy').childFile(artifactFileName); case HostArtifact.iproxy: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); - return _cache.getArtifactDirectory('usbmuxd').childFile(artifactFileName); + return _cache.getArtifactDirectory('libusbmuxd').childFile(artifactFileName); case HostArtifact.impellerc: case HostArtifact.libtessellator: final String artifactFileName = _hostArtifactToFileName(artifact, _platform); @@ -1348,7 +1345,6 @@ class CachedLocalEngineArtifacts implements Artifacts { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.web_javascript: @@ -1577,7 +1573,6 @@ class CachedLocalWebSdkArtifacts implements Artifacts { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.web_javascript: diff --git a/packages/flutter_tools/lib/src/base/file_system.dart b/packages/flutter_tools/lib/src/base/file_system.dart index d2a302b23235d..e07e5574fab92 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -63,7 +63,17 @@ class FileSystemUtils { /// /// On Windows it replaces all '\' with '\\'. On other platforms, it returns the /// path unchanged. - String escapePath(String path) => _platform.isWindows ? path.replaceAll(r'\', r'\\') : path; + String escapePath(String path) { + if (_platform.isWindows) { + path = path.replaceAll(r'\', r'\\'); + if (path.startsWith(RegExp('[a-z]:'))) { + // ensure that the drive letter is upper case see + // https://youtrack.jetbrains.com/issue/IDEA-329756/Importing-symlinked-Gradle-included-build-fails#focus=Comments-27-11721320.0-0 + return path[0].toUpperCase() + path.substring(1); + } + } + return path; + } /// Returns true if the file system [entity] has not been modified since the /// latest modification to [referenceFile]. diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 07414db3ff424..0ebd2354dfae5 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -17,6 +17,7 @@ import 'base/os.dart'; import 'base/utils.dart'; import 'convert.dart'; import 'globals.dart' as globals; +import 'runner/flutter_command.dart' show FlutterOptions; /// Whether icon font subsetting is enabled by default. const bool kIconTreeShakerEnabledDefault = true; @@ -32,6 +33,7 @@ class BuildInfo { List? extraGenSnapshotOptions, List? fileSystemRoots, this.androidProjectArgs = const [], + this.androidGradleProjectCacheDir, this.fileSystemScheme, this.buildNumber, this.buildName, @@ -50,6 +52,7 @@ class BuildInfo { this.assumeInitializeFromDillUpToDate = false, this.buildNativeAssets = true, this.useLocalCanvasKit = false, + this.webEnableHotReload = false, }) : extraFrontEndOptions = extraFrontEndOptions ?? const [], extraGenSnapshotOptions = extraGenSnapshotOptions ?? const [], fileSystemRoots = fileSystemRoots ?? const [], @@ -156,6 +159,9 @@ class BuildInfo { /// flag. final List androidProjectArgs; + /// Specifies Gradle's project-specific cache directory. + final String? androidGradleProjectCacheDir; + /// The package configuration for the loaded application. /// /// This is captured once during startup, but the actual package configuration @@ -177,6 +183,9 @@ class BuildInfo { /// If set, web builds will use the locally built CanvasKit instead of using the CDN final bool useLocalCanvasKit; + /// If set, web builds with DDC will run with support for hot reload. + final bool webEnableHotReload; + /// Can be used when the actual information is not needed. static const BuildInfo dummy = BuildInfo( BuildMode.debug, @@ -259,13 +268,36 @@ class BuildInfo { /// The module system DDC is targeting, or null if not using DDC or the /// associated flag isn't present. // TODO(markzipan): delete this when DDC's AMD module system is deprecated, https://github.com/flutter/flutter/issues/142060. - DdcModuleFormat? get ddcModuleFormat => - _ddcModuleFormatAndCanaryFeaturesFromFrontEndArgs(extraFrontEndOptions).ddcModuleFormat; + DdcModuleFormat get ddcModuleFormat { + final DdcModuleFormat moduleFormat = + webEnableHotReload ? DdcModuleFormat.ddc : DdcModuleFormat.amd; + final DdcModuleFormat? parsedFormat = + _ddcModuleFormatAndCanaryFeaturesFromFrontEndArgs(extraFrontEndOptions).ddcModuleFormat; + if (parsedFormat != null && moduleFormat != parsedFormat) { + throw Exception( + 'Unsupported option combination:\n' + '${FlutterOptions.kWebExperimentalHotReload}: $webEnableHotReload\n' + '${FlutterOptions.kExtraFrontEndOptions}: --dartdevc-module-format=${parsedFormat.name}', + ); + } + return moduleFormat; + } /// Whether to enable canary features when using DDC, or null if not using /// DDC or the associated flag isn't present. - bool? get canaryFeatures => - _ddcModuleFormatAndCanaryFeaturesFromFrontEndArgs(extraFrontEndOptions).canaryFeatures; + bool get canaryFeatures { + final bool canaryEnabled = webEnableHotReload; + final bool? parsedCanary = + _ddcModuleFormatAndCanaryFeaturesFromFrontEndArgs(extraFrontEndOptions).canaryFeatures; + if (parsedCanary != null && canaryEnabled != parsedCanary) { + throw Exception( + 'Unsupported option combination:\n' + '${FlutterOptions.kWebExperimentalHotReload}: $webEnableHotReload\n' + '${FlutterOptions.kExtraFrontEndOptions}: --dartdevc-canary=$parsedCanary', + ); + } + return canaryEnabled; + } /// Convert to a structured string encoded structure appropriate for usage /// in build system [Environment.defines]. @@ -339,6 +371,7 @@ class BuildInfo { '-Pperformance-measurement-file=$performanceMeasurementFile', if (codeSizeDirectory != null) '-Pcode-size-directory=$codeSizeDirectory', for (final String projectArg in androidProjectArgs) '-P$projectArg', + if (androidGradleProjectCacheDir != null) '--project-cache-dir=$androidGradleProjectCacheDir', ]; } } @@ -369,8 +402,6 @@ class AndroidBuildInfo { /// The target platforms for the build. final Iterable targetArchs; - bool get containsX86Target => targetArchs.contains(AndroidArch.x86); - /// Whether to bootstrap an empty application. final bool fastStart; } @@ -449,8 +480,7 @@ String? validatedBuildNumberForPlatform( } if (targetPlatform == TargetPlatform.android_arm || targetPlatform == TargetPlatform.android_arm64 || - targetPlatform == TargetPlatform.android_x64 || - targetPlatform == TargetPlatform.android_x86) { + targetPlatform == TargetPlatform.android_x64) { // See versionCode at https://developer.android.com/studio/publish/versioning final RegExp disallowed = RegExp(r'[^\d]'); String tmpBuildNumberStr = buildNumber.replaceAll(disallowed, ''); @@ -502,8 +532,7 @@ String? validatedBuildNameForPlatform( if (targetPlatform == TargetPlatform.android || targetPlatform == TargetPlatform.android_arm || targetPlatform == TargetPlatform.android_arm64 || - targetPlatform == TargetPlatform.android_x64 || - targetPlatform == TargetPlatform.android_x86) { + targetPlatform == TargetPlatform.android_x64) { // See versionName at https://developer.android.com/studio/publish/versioning return buildName; } @@ -542,8 +571,7 @@ enum TargetPlatform { // and [AndroidArch]. android_arm, android_arm64, - android_x64, - android_x86; + android_x64; String get fuchsiaArchForTargetPlatform { switch (this) { @@ -555,7 +583,6 @@ enum TargetPlatform { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.darwin: case TargetPlatform.ios: case TargetPlatform.linux_arm64: @@ -581,7 +608,6 @@ enum TargetPlatform { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.ios: @@ -619,21 +645,18 @@ enum DarwinArch { enum AndroidArch { armeabi_v7a, arm64_v8a, - x86, x86_64; String get archName => switch (this) { AndroidArch.armeabi_v7a => 'armeabi-v7a', AndroidArch.arm64_v8a => 'arm64-v8a', AndroidArch.x86_64 => 'x86_64', - AndroidArch.x86 => 'x86', }; String get platformName => switch (this) { AndroidArch.armeabi_v7a => 'android-arm', AndroidArch.arm64_v8a => 'android-arm64', AndroidArch.x86_64 => 'android-x64', - AndroidArch.x86 => 'android-x86', }; } @@ -703,7 +726,6 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch? darwinArch TargetPlatform.android_arm => 'android-arm', TargetPlatform.android_arm64 => 'android-arm64', TargetPlatform.android_x64 => 'android-x64', - TargetPlatform.android_x86 => 'android-x86', TargetPlatform.linux_x64 => 'linux-x64', TargetPlatform.linux_arm64 => 'linux-arm64', TargetPlatform.windows_x64 => 'windows-x64', @@ -722,7 +744,6 @@ TargetPlatform getTargetPlatformForName(String platform) { 'android-arm' => TargetPlatform.android_arm, 'android-arm64' => TargetPlatform.android_arm64, 'android-x64' => TargetPlatform.android_x64, - 'android-x86' => TargetPlatform.android_x86, 'fuchsia-arm64' => TargetPlatform.fuchsia_arm64, 'fuchsia-x64' => TargetPlatform.fuchsia_x64, 'ios' => TargetPlatform.ios, @@ -744,7 +765,6 @@ AndroidArch getAndroidArchForName(String platform) { 'android-arm' => AndroidArch.armeabi_v7a, 'android-arm64' => AndroidArch.arm64_v8a, 'android-x64' => AndroidArch.x86_64, - 'android-x86' => AndroidArch.x86, _ => throw Exception('Unsupported Android arch name "$platform"'), }; } @@ -999,9 +1019,6 @@ const String kXcodeAction = 'Action'; /// to the BUILT_PRODUCTS_DIR prior to the build. const String kXcodePreAction = 'PreBuildAction'; -// Whether the last Flutter tool invocation enabled dev dependencies. -const String kDevDependenciesEnabled = 'DevDependenciesEnabled'; - final Converter _defineEncoder = utf8.encoder.fuse(base64.encoder); final Converter _defineDecoder = base64.decoder.fuse(utf8.decoder); diff --git a/packages/flutter_tools/lib/src/build_system/depfile.dart b/packages/flutter_tools/lib/src/build_system/depfile.dart index f575bb3019096..1114faf13910c 100644 --- a/packages/flutter_tools/lib/src/build_system/depfile.dart +++ b/packages/flutter_tools/lib/src/build_system/depfile.dart @@ -66,16 +66,19 @@ class DepfileService { } void _writeFilesToBuffer(List files, StringBuffer buffer) { + final bool backslash = _fileSystem.path.style.separator == r'\'; for (final File outputFile in files) { - if (_fileSystem.path.style.separator == r'\') { - // backslashes and spaces in a depfile have to be escaped if the - // platform separator is a backslash. - final String path = outputFile.path.replaceAll(r'\', r'\\').replaceAll(r' ', r'\ '); - buffer.write(' $path'); + String path = _fileSystem.path.normalize(outputFile.path); + if (backslash) { + // Backslashes in a depfile have to be escaped if the platform separator is a backslash. + path = path.replaceAll(r'\', r'\\'); } else { - final String path = outputFile.path.replaceAll(r' ', r'\ '); - buffer.write(' $path'); + // Convert all path separators to forward slashes. + path = path.replaceAll(r'\', r'/'); } + // Escape spaces. + path = path.replaceAll(r' ', r'\ '); + buffer.write(' $path'); } } @@ -93,7 +96,8 @@ class DepfileService { // The tool doesn't write duplicates to these lists. This call is an attempt to // be resilient to the outputs of other tools which write or user edits to depfiles. .toSet() - .map(_fileSystem.file) + // Normalize the path before creating a file object. + .map((String path) => _fileSystem.file(_fileSystem.path.normalize(path))) .toList(); } } 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 735c380b10f84..5d4ec0b073a03 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -6,16 +6,14 @@ import 'package:package_config/package_config.dart'; import '../../artifacts.dart'; import '../../base/build.dart'; -import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; import '../../compile.dart'; import '../../dart/package_map.dart'; import '../../devfs.dart'; -import '../../globals.dart' as globals show platform, xcode; +import '../../globals.dart' as globals show xcode; import '../../project.dart'; -import '../../runner/flutter_command.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -127,11 +125,6 @@ class ReleaseCopyFlutterBundle extends CopyFlutterBundle { } /// Generate a snapshot of the dart code used in the program. -/// -/// This target depends on the `.dart_tool/package_config.json` file -/// even though it is not listed as an input. Pub inserts a timestamp into -/// the file which causes unnecessary rebuilds, so instead a subset of the contents -/// are used an input instead. class KernelSnapshot extends Target { const KernelSnapshot(); @@ -140,7 +133,7 @@ class KernelSnapshot extends Target { @override List get inputs => const [ - Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config_subset'), + Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), Source.pattern( '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart', ), @@ -223,7 +216,6 @@ class KernelSnapshot extends Target { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.ios: @@ -238,8 +230,7 @@ class KernelSnapshot extends Target { TargetPlatform.android || TargetPlatform.android_arm || TargetPlatform.android_arm64 || - TargetPlatform.android_x64 || - TargetPlatform.android_x86 => 'android', + TargetPlatform.android_x64 => 'android', TargetPlatform.darwin => 'macos', TargetPlatform.ios => 'ios', TargetPlatform.linux_arm64 || TargetPlatform.linux_x64 => 'linux', @@ -310,15 +301,17 @@ class KernelSnapshot extends Target { if (flavor == null) { return; } - if (globals.platform.environment[kAppFlavor] != null) { - throwToolExit('$kAppFlavor is used by the framework and cannot be set in the environment.'); - } - if (dartDefines.any((String define) => define.startsWith(kAppFlavor))) { - throwToolExit( - '$kAppFlavor is used by the framework and cannot be ' - 'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}', - ); - } + + // It is possible there is a flavor already in dartDefines, from another + // part of the build process, but this should take precedence as it happens + // last (xcodebuild execution). + // + // See https://github.com/flutter/flutter/issues/169598. + + // If the flavor is already in the dart defines, remove it. + dartDefines.removeWhere((String define) => define.startsWith(kAppFlavor)); + + // Then, add it to the end. dartDefines.add('$kAppFlavor=$flavor'); } } diff --git a/packages/flutter_tools/lib/src/build_system/targets/dart_plugin_registrant.dart b/packages/flutter_tools/lib/src/build_system/targets/dart_plugin_registrant.dart index c77bda8f2fe2d..0a67a98121065 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/dart_plugin_registrant.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/dart_plugin_registrant.dart @@ -68,7 +68,7 @@ class DartPluginRegistrantTarget extends Target { @override List get inputs => [ - const Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config_subset'), + const Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), ]; @override diff --git a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart index 60fe4ac4bfb66..92f36377b1fef 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart @@ -5,155 +5,9 @@ import 'package:meta/meta.dart'; import '../../artifacts.dart'; -import '../../base/common.dart'; -import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; -import '../../flutter_plugins.dart'; -import '../../globals.dart' as globals; -import '../../project.dart'; import '../build_system.dart'; -import '../exceptions.dart'; - -/// A target that checks that dev dependencies are enabled on debug/profile -/// builds and disabled on release builds. -/// -/// The Flutter tool enables/disables dev dependencies using the build mode. -/// These can get out of sync if the user switches the build mode in Xcode. -/// -/// Implementers should override [CheckDevDependencies.inputs] to add a [Source] -/// that changes when dev dependencies status changes. -abstract class CheckDevDependencies extends Target { - const CheckDevDependencies(); - - @override - List get dependencies => []; - - @override - List get inputs => [ - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/darwin.dart', - ), - Source.fromProject((FlutterProject project) => project.flutterPluginsDependenciesFile), - ]; - - @override - List get outputs => const []; - - // The command that turns on dev dependencies. - // Displayed in the error message if dev dependencies are off in a debug build. - @visibleForOverriding - String get debugBuildCommand; - - // The command that turns on dev dependencies. - // Displayed in the error message if dev dependencies are off in a profile build. - @visibleForOverriding - String get profileBuildCommand; - - // The command that turns off dev dependencies. - // Displayed in the error message if dev dependencies are off in a release build. - @visibleForOverriding - String get releaseBuildCommand; - - // Check that dev dependencies are enabled on debug or profile builds and - // disabled on release builds. - // - // The Flutter tool enables/disables dev dependencies using the build mode. - // These can get out of sync if the user switches the build mode in Xcode. - @override - Future build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment); - final String? devDependenciesEnabledString = environment.defines[kDevDependenciesEnabled]; - if (devDependenciesEnabledString == null) { - throw MissingDefineException(kDevDependenciesEnabled, name); - } - - final bool? devDependenciesEnabled = bool.tryParse( - environment.defines[kDevDependenciesEnabled] ?? '', - ); - if (devDependenciesEnabled == null) { - throw Exception( - 'Unexpected $kDevDependenciesEnabled define value: "$devDependenciesEnabledString"', - ); - } - - if (devDependenciesEnabled && buildMode.isRelease) { - // Supress this error if the project has no dev dependencies. - if (!_hasDevDependencies(environment)) { - environment.logger.printTrace( - 'Ignoring dev dependencies error as the project has no dev dependencies', - ); - return; - } - - _printXcodeError( - 'Release builds should not have Dart dev dependencies enabled\n' - '\n' - 'This error happens if:\n' - '\n' - '1. Your pubspec.yaml has dev dependencies\n' - '2. Your last Flutter CLI action turned on dev dependencies\n' - '3. You do a release build in Xcode\n' - '\n' - 'You can turn off Dart dev dependencies by running this in your Flutter project:\n' - '\n' - ' $releaseBuildCommand\n' - '\n', - ); - throwToolExit('Dev dependencies enabled in release build'); - } else if (!devDependenciesEnabled && !buildMode.isRelease) { - // Supress this error if the project has no dev dependencies. - if (!_hasDevDependencies(environment)) { - environment.logger.printTrace( - 'Ignoring dev dependencies error as the project has no dev dependencies', - ); - return; - } - - final bool profile = buildMode == BuildMode.profile; - _printXcodeError( - '${profile ? 'Profile' : 'Debug'} builds require Dart dev dependencies\n' - '\n' - 'This error happens if:\n' - '\n' - '1. Your pubspec.yaml has dev dependencies\n' - '2. Your last Flutter CLI action turned off dev dependencies\n' - '3. You do a debug or profile build in Xcode\n' - '\n' - 'You can turn on Dart dev dependencies by running this in your Flutter project:\n' - '\n' - ' ${profile ? profileBuildCommand : debugBuildCommand}\n' - '\n', - ); - throwToolExit('Dev dependencies disabled in ${profile ? 'profile' : 'debug'} build'); - } - } - - // Check if the iOS project has Dart dev dependencies. On error, assumes true. - bool _hasDevDependencies(Environment environment) { - // If the app has no plugins, the .flutter-plugins-dependencies file isn't generated. - final FlutterProject project = FlutterProject.fromDirectory(environment.projectDir); - final File pluginsFile = project.flutterPluginsDependenciesFile; - if (!pluginsFile.existsSync()) { - return false; - } - - try { - return flutterPluginsListHasDevDependencies(pluginsFile); - } on Exception catch (e) { - environment.logger.printWarning('Unable to parse .flutter-plugins-dependencies file:\n$e'); - return true; - } - } - - void _printXcodeError(String message) { - globals.stdio.stderrWrite('error: $message'); - } -} abstract class UnpackDarwin extends Target { const UnpackDarwin(); 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 85c36f9b61180..ac7234a196761 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -10,6 +10,7 @@ import '../../base/build.dart'; import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; +import '../../base/logger.dart' show Logger; import '../../base/process.dart'; import '../../base/version.dart'; import '../../build_info.dart'; @@ -365,6 +366,126 @@ class DebugUnpackIOS extends UnpackIOS { BuildMode get buildMode => BuildMode.debug; } +// TODO(gaaclarke): Remove this after a reasonable amount of time where the +// UISceneDelegate migration being on stable. This incurs a minor build time +// cost. +Future _checkForLaunchRootViewControllerAccessDeprecation( + Logger logger, + File file, + Pattern usage, + Pattern terminator, +) async { + final List lines = file.readAsLinesSync(); + + bool inDidFinishLaunchingWithOptions = false; + int lineNumber = 0; + for (final String line in lines) { + lineNumber += 1; + if (!inDidFinishLaunchingWithOptions) { + if (line.contains('didFinishLaunchingWithOptions')) { + inDidFinishLaunchingWithOptions = true; + } + } else { + if (line.startsWith(terminator)) { + inDidFinishLaunchingWithOptions = false; + } else if (line.contains(usage)) { + _printWarning( + logger, + file.path, + lineNumber, + // TODO(gaaclarke): Add a link to the migration guide when it's written. + 'Flutter deprecation: Accessing rootViewController in `application:didFinishLaunchingWithOptions:` [flutter-launch-rootvc].\n' + '\tnote: \n' // The space after `note:` is meaningful, it is required associate the note with the warning in Xcode. + '\tAfter the UISceneDelegate migration the `UIApplicationDelegate.window` and ' + '`UIWindow.rootViewController` properties will not be set in ' + '`application:didFinishLaunchingWithOptions:`. If you are relying on that ' + 'in order to register platform channels at application launch use the ' + '`FlutterPluginRegistry` API instead. Other setup can be moved to a ' + 'FlutterViewController subclass (ex: `awakeFromNib`).', + ); + } + } + } +} + +/// Checks [file] representing objc code for deprecated usage of the +/// rootViewController and writes it to [logger]. +@visibleForTesting +Future checkForLaunchRootViewControllerAccessDeprecationObjc(Logger logger, File file) async { + try { + await _checkForLaunchRootViewControllerAccessDeprecation( + logger, + file, + RegExp('self.*?window.*?rootViewController'), + RegExp('^}'), + ); + // ignore: avoid_catches_without_on_clauses + } catch (_) {} +} + +/// Checks [file] representing swift code for deprecated usage of the +/// rootViewController and writes it to [logger]. +@visibleForTesting +Future checkForLaunchRootViewControllerAccessDeprecationSwift( + Logger logger, + File file, +) async { + try { + await _checkForLaunchRootViewControllerAccessDeprecation( + logger, + file, + 'window?.rootViewController', + RegExp(r'^.*?func\s*?\S*?\('), + ); + // ignore: avoid_catches_without_on_clauses + } catch (_) {} +} + +void _printWarning(Logger logger, String path, int line, String warning) { + logger.printWarning('$path:$line: warning: $warning'); +} + +class _IssueLaunchRootViewControllerAccess extends Target { + const _IssueLaunchRootViewControllerAccess(); + + @override + Future build(Environment environment) async { + final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir); + if (flutterProject.ios.appDelegateSwift.existsSync()) { + await checkForLaunchRootViewControllerAccessDeprecationSwift( + environment.logger, + flutterProject.ios.appDelegateSwift, + ); + } + if (flutterProject.ios.appDelegateObjc.existsSync()) { + await checkForLaunchRootViewControllerAccessDeprecationObjc( + environment.logger, + flutterProject.ios.appDelegateObjc, + ); + } + } + + @override + List get dependencies => []; + + @override + List get inputs { + return [ + const Source.pattern( + '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart', + ), + Source.fromProject((FlutterProject project) => project.ios.appDelegateObjc, optional: true), + Source.fromProject((FlutterProject project) => project.ios.appDelegateSwift, optional: true), + ]; + } + + @override + String get name => 'IssueLaunchRootViewControllerAccess'; + + @override + List get outputs => []; +} + abstract class IosLLDBInit extends Target { const IosLLDBInit(); @@ -484,37 +605,6 @@ class DebugIosLLDBInit extends IosLLDBInit { BuildMode get buildMode => BuildMode.debug; } -class CheckDevDependenciesIos extends CheckDevDependencies { - const CheckDevDependenciesIos(); - - @override - String get name => 'check_dev_dependencies_ios'; - - @override - List get inputs { - return [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart', - ), - - // The generated Xcode properties file contains - // the FLUTTER_DEV_DEPENDENCIES_ENABLED configuration. - // This target should re-run whenever that value changes. - Source.fromProject((FlutterProject project) => project.ios.generatedXcodePropertiesFile), - ]; - } - - @override - String get debugBuildCommand => 'flutter build ios --config-only --debug'; - - @override - String get profileBuildCommand => 'flutter build ios --config-only --profile'; - - @override - String get releaseBuildCommand => 'flutter build ios --config-only --release'; -} - /// The base class for all iOS bundle targets. /// /// This is responsible for setting up the basic App.framework structure, including: @@ -526,7 +616,11 @@ abstract class IosAssetBundle extends Target { const IosAssetBundle(); @override - List get dependencies => const [KernelSnapshot(), InstallCodeAssets()]; + List get dependencies => const [ + KernelSnapshot(), + InstallCodeAssets(), + _IssueLaunchRootViewControllerAccess(), + ]; @override List get inputs => const [ @@ -667,7 +761,6 @@ class DebugIosApplicationBundle extends IosAssetBundle { @override List get dependencies => [ - const CheckDevDependenciesIos(), const DebugUniversalFramework(), const DebugIosLLDBInit(), ...super.dependencies, @@ -699,11 +792,7 @@ class ProfileIosApplicationBundle extends _IosAssetBundleWithDSYM { String get name => 'profile_ios_bundle_flutter_assets'; @override - List get dependencies => const [ - CheckDevDependenciesIos(), - AotAssemblyProfile(), - InstallCodeAssets(), - ]; + List get dependencies => const [AotAssemblyProfile(), InstallCodeAssets()]; } /// Build a release iOS application bundle. @@ -714,11 +803,7 @@ class ReleaseIosApplicationBundle extends _IosAssetBundleWithDSYM { String get name => 'release_ios_bundle_flutter_assets'; @override - List get dependencies => const [ - CheckDevDependenciesIos(), - AotAssemblyRelease(), - InstallCodeAssets(), - ]; + List get dependencies => const [AotAssemblyRelease(), InstallCodeAssets()]; @override Future build(Environment environment) async { diff --git a/packages/flutter_tools/lib/src/build_system/targets/localizations.dart b/packages/flutter_tools/lib/src/build_system/targets/localizations.dart index c982699a6c60e..6f96217eb65d1 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/localizations.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/localizations.dart @@ -4,7 +4,6 @@ import '../../base/file_system.dart'; import '../../convert.dart'; -import '../../features.dart'; import '../../localizations/gen_l10n.dart'; import '../../localizations/localizations_utils.dart'; import '../build_system.dart'; @@ -60,7 +59,6 @@ class GenerateLocalizationsTarget extends Target { logger: environment.logger, fileSystem: environment.fileSystem, defaultArbDir: defaultArbDir, - defaultSyntheticPackage: !featureFlags.isExplicitPackageDependenciesEnabled, ); await generateLocalizations( logger: environment.logger, 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 8b415a013d44d..72aa7c8ba9b40 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -559,7 +559,6 @@ class DebugMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), KernelSnapshot(), DebugMacOSFramework(), DebugUnpackMacOS(), @@ -606,7 +605,6 @@ class ProfileMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), CompileMacOSFramework(), InstallCodeAssets(), ProfileUnpackMacOS(), @@ -634,7 +632,6 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), CompileMacOSFramework(), InstallCodeAssets(), ReleaseUnpackMacOS(), @@ -675,34 +672,3 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { } } } - -class CheckDevDependenciesMacOS extends CheckDevDependencies { - const CheckDevDependenciesMacOS(); - - @override - String get name => 'check_dev_dependencies_macos'; - - @override - List get inputs { - return [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/macos.dart', - ), - - // The generated Xcode properties file contains - // the FLUTTER_DEV_DEPENDENCIES_ENABLED configuration. - // This target should re-run whenever that value changes. - Source.fromProject((FlutterProject project) => project.macos.generatedXcodePropertiesFile), - ]; - } - - @override - String get debugBuildCommand => 'flutter build macos --config-only --debug'; - - @override - String get profileBuildCommand => 'flutter build macos --config-only --profile'; - - @override - String get releaseBuildCommand => 'flutter build macos --config-only --release'; -} diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 792e4e066e965..23644bdbdfd93 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -41,6 +41,15 @@ abstract class DartBuild extends Target { final Uri projectUri = environment.projectDir.uri; final String? runPackageName = packageConfig.packages.where((Package p) => p.root == projectUri).firstOrNull?.name; + if (runPackageName == null) { + throw StateError( + 'Could not determine run package name. ' + 'Project path "${projectUri.toFilePath()}" did not occur as package ' + 'root in package config "${environment.packageConfigPath}". ' + 'Please report a reproduction on ' + 'https://github.com/flutter/flutter/issues/169475.', + ); + } final String pubspecPath = packageConfigFile.uri.resolve('../pubspec.yaml').toFilePath(); final FlutterNativeAssetsBuildRunner buildRunner = _buildRunner ?? @@ -49,7 +58,7 @@ abstract class DartBuild extends Target { packageConfig, fileSystem, environment.logger, - runPackageName!, + runPackageName, pubspecPath, ); result = await runFlutterSpecificDartBuild( @@ -77,7 +86,7 @@ abstract class DartBuild extends Target { } environment.depFileService.writeToFile(depfile, outputDepfile); if (!await outputDepfile.exists()) { - throwToolExit("${outputDepfile.path} doesn't exist."); + throw StateError("${outputDepfile.path} doesn't exist."); } } @@ -90,7 +99,7 @@ abstract class DartBuild extends Target { '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart', ), // If different packages are resolved, different native assets might need to be built. - Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config_subset'), + Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), // TODO(mosuem): Should consume resources.json. https://github.com/flutter/flutter/issues/146263 ]; @@ -178,7 +187,7 @@ class InstallCodeAssets extends Target { '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart', ), // If different packages are resolved, different native assets might need to be built. - Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config_subset'), + Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), ]; @override diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart index e6775432fcf73..2636556a70a4a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/web.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart @@ -132,7 +132,7 @@ abstract class Dart2WebTarget extends Target { const Source.hostArtifact(HostArtifact.flutterWebSdk), const Source.artifact(Artifact.engineDartBinary), const Source.pattern('{BUILD_DIR}/main.dart'), - const Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config_subset'), + const Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), ]; @override @@ -181,7 +181,8 @@ class Dart2JSTarget extends Dart2WebTarget { for (final String dartDefine in computeDartDefines(environment)) '-D$dartDefine', ]; - final List compilationArgs = [ + // NOTE: most args should be populated in [toSharedCommandOptions]. + final List cfeCompilationArgs = [ ...sharedCommandOptions, ...compilerConfig.toSharedCommandOptions(buildMode), '-o', @@ -198,7 +199,7 @@ class Dart2JSTarget extends Dart2WebTarget { // Run the dart2js compilation in two stages, so that icon tree shaking can // parse the kernel file for web builds. - await processUtils.run(compilationArgs, throwOnError: true); + await processUtils.run(cfeCompilationArgs, throwOnError: true); final File outputJSFile = environment.buildDir.childFile('main.dart.js'); @@ -337,7 +338,6 @@ class Dart2WasmTarget extends Dart2WebTarget { ...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions), for (final String dartDefine in dartDefines) '-D$dartDefine', '--extra-compiler-option=--depfile=${depFile.path}', - ...compilerConfig.toCommandOptions(buildMode), '-o', outputWasmFile.path, diff --git a/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart b/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart index 96a774c2340d7..9d9fbc35c1b4f 100644 --- a/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart +++ b/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart @@ -114,7 +114,7 @@ final class AssetTransformer { final List transformerArguments = [ '--input=${asset.absolute.path}', '--output=${output.absolute.path}', - ...?transformer.args, + ...transformer.args, ]; final List command = [ diff --git a/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart b/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart index af85ca60a2546..3916182837ef3 100644 --- a/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart +++ b/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart @@ -107,7 +107,6 @@ class ShaderCompiler { List _shaderTargetsFromTargetPlatform(TargetPlatform targetPlatform) { switch (targetPlatform) { case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android: diff --git a/packages/flutter_tools/lib/src/commands/build_aar.dart b/packages/flutter_tools/lib/src/commands/build_aar.dart index a81534ec166f9..f8c6c91c0ddf5 100644 --- a/packages/flutter_tools/lib/src/commands/build_aar.dart +++ b/packages/flutter_tools/lib/src/commands/build_aar.dart @@ -53,7 +53,7 @@ class BuildAarCommand extends BuildSubCommand { argParser.addMultiOption( 'target-platform', defaultsTo: ['android-arm', 'android-arm64', 'android-x64'], - allowed: ['android-arm', 'android-arm64', 'android-x86', 'android-x64'], + allowed: ['android-arm', 'android-arm64', 'android-x64'], help: 'The target platform for which the project is compiled.', ); } diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart index 656bb2b16617b..6d1e1def1f05e 100644 --- a/packages/flutter_tools/lib/src/commands/build_apk.dart +++ b/packages/flutter_tools/lib/src/commands/build_apk.dart @@ -50,7 +50,7 @@ class BuildApkCommand extends BuildSubCommand { ) ..addMultiOption( 'target-platform', - allowed: ['android-arm', 'android-arm64', 'android-x86', 'android-x64'], + allowed: ['android-arm', 'android-arm64', 'android-x64'], help: 'The target platform for which the app is compiled.', ); usesTrackWidgetCreation(verboseHelp: verboseHelp); @@ -72,7 +72,6 @@ class BuildApkCommand extends BuildSubCommand { static const List _kDefaultJitArchs = [ 'android-arm', 'android-arm64', - 'android-x86', 'android-x64', ]; static const List _kDefaultAotArchs = [ diff --git a/packages/flutter_tools/lib/src/commands/build_bundle.dart b/packages/flutter_tools/lib/src/commands/build_bundle.dart index ec06e8dcbeb61..4e0decb1c3f20 100644 --- a/packages/flutter_tools/lib/src/commands/build_bundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_bundle.dart @@ -41,7 +41,6 @@ class BuildBundleCommand extends BuildSubCommand { allowed: const [ 'android-arm', 'android-arm64', - 'android-x86', 'android-x64', 'ios', 'darwin', @@ -130,7 +129,6 @@ class BuildBundleCommand extends BuildSubCommand { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.ios: 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 b1fd7ce6c2ceb..c4b37a78e954a 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -17,7 +17,6 @@ import '../build_info.dart'; import '../build_system/build_system.dart'; import '../build_system/targets/ios.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../macos/cocoapod_utils.dart'; @@ -487,11 +486,6 @@ end final Status status = globals.logger.startProgress(' ├─Building App.xcframework...'); final List frameworks = []; - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; - try { for (final EnvironmentType sdkType in EnvironmentType.values) { final Directory outputBuildDirectory = switch (sdkType) { @@ -514,7 +508,6 @@ end globals.artifacts!, ).map((DarwinArch e) => e.name).join(' '), kSdkRoot: await globals.xcode!.sdkLocation(sdkType), - kDevDependenciesEnabled: devDependenciesEnabled.toString(), ...buildInfo.toBuildSystemEnvironment(), }, artifacts: globals.artifacts!, 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 9ce44f3f9d54f..3dc4bc3eedb87 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart @@ -15,7 +15,6 @@ import '../build_info.dart'; import '../build_system/build_system.dart'; import '../build_system/targets/macos.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../macos/cocoapod_utils.dart'; @@ -234,10 +233,6 @@ end ) async { final Status status = globals.logger.startProgress(' ├─Building App.xcframework...'); try { - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; final Environment environment = Environment( projectDir: globals.fs.currentDirectory, packageConfigPath: packageConfigPath(), @@ -251,7 +246,6 @@ end kDarwinArchs: defaultMacOSArchsForEnvironment( globals.artifacts!, ).map((DarwinArch e) => e.name).join(' '), - kDevDependenciesEnabled: devDependenciesEnabled.toString(), ...buildInfo.toBuildSystemEnvironment(), }, artifacts: globals.artifacts!, diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index f930f2fbfa894..003503dfa0eb3 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -175,7 +175,7 @@ class BuildWebCommand extends BuildSubCommand { ); final bool sourceMaps = boolArg('source-maps'); - final bool minify = boolArg('minify'); + final bool? minify = argResults!.wasParsed('minify') ? boolArg('minify') : null; final List compilerConfigs; diff --git a/packages/flutter_tools/lib/src/commands/clean.dart b/packages/flutter_tools/lib/src/commands/clean.dart index 97f6c69c58ec3..b3a90533f9145 100644 --- a/packages/flutter_tools/lib/src/commands/clean.dart +++ b/packages/flutter_tools/lib/src/commands/clean.dart @@ -6,6 +6,7 @@ import 'package:meta/meta.dart'; import '../../src/macos/xcode.dart'; import '../base/common.dart'; +import '../base/error_handling_io.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; import '../build_info.dart'; @@ -68,7 +69,6 @@ class CleanCommand extends FlutterCommand { deleteFile(flutterProject.macos.ephemeralDirectory); deleteFile(flutterProject.windows.ephemeralDirectory); deleteFile(flutterProject.flutterPluginsDependenciesFile); - deleteFile(flutterProject.flutterPluginsFile); return const FlutterCommandResult(ExitStatus.success); } @@ -119,6 +119,16 @@ class CleanCommand extends FlutterCommand { @visibleForTesting void deleteFile(FileSystemEntity file) { + try { + ErrorHandlingFileSystem.noExitOnFailure(() { + _deleteFile(file); + }); + } on Exception catch (e) { + globals.printError('Failed to remove ${file.path}: $e'); + } + } + + void _deleteFile(FileSystemEntity file) { // This will throw a FileSystemException if the directory is missing permissions. try { if (!file.existsSync()) { diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart index dac09a2262bf7..97781410796e2 100644 --- a/packages/flutter_tools/lib/src/commands/config.dart +++ b/packages/flutter_tools/lib/src/commands/config.dart @@ -67,7 +67,7 @@ class ConfigCommand extends FlutterCommand { hide: !verboseHelp, help: 'Print config values as json.', ); - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting == null) { continue; @@ -132,7 +132,7 @@ class ConfigCommand extends FlutterCommand { } if (boolArg('clear-features')) { - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting != null) { globals.config.removeValue(configSetting); @@ -188,7 +188,7 @@ class ConfigCommand extends FlutterCommand { _updateConfig('build-dir', buildDir); } - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting == null) { continue; @@ -247,14 +247,14 @@ class ConfigCommand extends FlutterCommand { String get settingsText { final Map featuresByName = {}; final String channel = globals.flutterVersion.channel; - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting != null) { featuresByName[configSetting] = feature; } } final Set keys = { - ...allFeatures.map((Feature e) => e.configSetting).whereType(), + ...featureFlags.allFeatures.map((Feature e) => e.configSetting).whereType(), ...globals.config.keys, }; final Iterable settings = keys.map((String key) { diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index dd3a50f3ab88c..d0e43c601ac1b 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -12,11 +12,8 @@ import '../android/gradle_utils.dart' as gradle; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/utils.dart'; -import '../build_info.dart'; -import '../build_system/build_system.dart'; import '../cache.dart'; import '../convert.dart'; -import '../dart/generate_synthetic_packages.dart'; import '../flutter_project_metadata.dart'; import '../globals.dart' as globals; import '../project.dart'; @@ -494,31 +491,6 @@ mixin CreateBase on FlutterCommand { final bool windowsPlatform = templateContext['windows'] as bool? ?? false; final bool webPlatform = templateContext['web'] as bool? ?? false; - if (shouldCallPubGet) { - final Environment environment = Environment( - artifacts: globals.artifacts!, - logger: globals.logger, - cacheDir: globals.cache.getRoot(), - engineVersion: globals.flutterVersion.engineRevision, - fileSystem: globals.fs, - flutterRootDir: globals.fs.directory(Cache.flutterRoot), - outputDir: globals.fs.directory(getBuildDirectory()), - processManager: globals.processManager, - platform: globals.platform, - analytics: globals.analytics, - projectDir: project.directory, - packageConfigPath: packageConfigPath(), - generateDartPluginRegistry: true, - ); - - // Generate the l10n synthetic package that will be injected into the - // package_config in the call to pub.get() below. - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: globals.buildSystem, - buildTargets: globals.buildTargets, - ); - } final List platformsForMigrateConfig = [ SupportedPlatform.root, ]; diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index 53b5c43e0dc8c..186a6c7a1456c 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -8,7 +8,6 @@ import '../artifacts.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; -import '../features.dart'; import '../localizations/gen_l10n.dart'; import '../localizations/localizations_utils.dart'; import '../runner/flutter_command.dart'; @@ -36,16 +35,16 @@ class GenerateLocalizationsCommand extends FlutterCommand { argParser.addOption( 'output-dir', help: - 'The directory where the generated localization classes will be written ' - 'if the synthetic-package flag is set to false.\n' - '\n' - 'If output-dir is specified and the synthetic-package flag is enabled, ' - 'this option will be ignored by the tool.\n' + 'The directory where the generated localization classes will be written.' '\n' 'The app must import the file specified in the "--output-localization-file" ' 'option from this directory. If unspecified, this defaults to the same ' 'directory as the input directory specified in "--arb-dir".', ); + argParser.addFlag( + 'synthetic-package', + help: 'DEPRECATED. This flag cannot be enabled and should be removed.', + ); argParser.addOption( 'template-arb-file', help: @@ -149,19 +148,6 @@ class GenerateLocalizationsCommand extends FlutterCommand { '\n' 'When null, the JSON file will not be generated.', ); - argParser.addFlag( - 'synthetic-package', - defaultsTo: !featureFlags.isExplicitPackageDependenciesEnabled, - help: - 'Determines whether or not the generated output files will be ' - 'generated as a synthetic package or at a specified directory in ' - 'the Flutter project.\n' - '\n' - 'DEPRECATED: https://flutter.dev/to/flutter-gen-deprecation.\n' - '\n' - 'When synthetic-package is set to false, it will generate the ' - 'localizations files in the directory specified by arb-dir by default.\n', - ); argParser.addOption( 'project-dir', valueHelp: 'absolute/path/to/flutter/project', @@ -262,7 +248,6 @@ class GenerateLocalizationsCommand extends FlutterCommand { logger: _logger, fileSystem: _fileSystem, defaultArbDir: defaultArbDir, - defaultSyntheticPackage: !featureFlags.isExplicitPackageDependenciesEnabled, ); _logger.printStatus( 'Because l10n.yaml exists, the options defined there will be used ' diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart index 944da0c71595b..73ef3a32117e7 100644 --- a/packages/flutter_tools/lib/src/commands/packages.dart +++ b/packages/flutter_tools/lib/src/commands/packages.dart @@ -12,7 +12,6 @@ import '../build_info.dart'; import '../build_system/build_system.dart'; import '../build_system/targets/localizations.dart'; import '../cache.dart'; -import '../dart/generate_synthetic_packages.dart'; import '../dart/package_map.dart'; import '../dart/pub.dart'; import '../flutter_plugins.dart'; @@ -304,12 +303,7 @@ class PackagesGetCommand extends FlutterCommand { packageConfigPath: packageConfigPath(), generateDartPluginRegistry: true, ); - if (rootProject.manifest.generateLocalizations && - !await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: globals.buildSystem, - buildTargets: globals.buildTargets, - )) { + if (rootProject.manifest.generateLocalizations) { // If localizations were enabled, but we are not using synthetic packages. final BuildResult result = await globals.buildSystem.build( const GenerateLocalizationsTarget(), diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index f5a6d7062d78d..7c1b6bff9461a 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -5,114 +5,82 @@ import 'dart:async'; import 'dart:collection'; -import 'package:meta/meta.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; +import 'package:yaml/yaml.dart'; +import 'package:yaml_edit/yaml_edit.dart'; import '../base/common.dart'; import '../base/context.dart'; import '../base/file_system.dart'; -import '../base/logger.dart'; import '../base/net.dart'; -import '../base/task_queue.dart'; import '../cache.dart'; import '../dart/pub.dart'; import '../globals.dart' as globals; import '../project.dart'; import '../runner/flutter_command.dart'; import '../update_packages_pins.dart'; -import '../version.dart'; // Pub packages are rolled automatically by the flutter-pub-roller-bot // by using the `flutter update-packages --force-upgrade`. // For the latest status, see: // https://github.com/pulls?q=author%3Aflutter-pub-roller-bot +const String _pubspecName = 'pubspec.yaml'; + class UpdatePackagesCommand extends FlutterCommand { - UpdatePackagesCommand() { + UpdatePackagesCommand({required bool verboseHelp}) { argParser ..addFlag( - 'force-upgrade', + _keyForceUpgrade, help: 'Attempt to update all the dependencies to their latest versions.\n' 'This will actually modify the pubspec.yaml files in your checkout.', negatable: false, ) - ..addOption( - 'cherry-pick-package', - help: - 'Attempt to update only the specified package. The "--cherry-pick-version" version must be specified also.', - ) - ..addOption( - 'cherry-pick-version', - help: - 'Attempt to update the package to the specified version. The "--cherry-pick-package" option must be specified also.', - ) ..addFlag( - 'paths', - help: - 'Finds paths in the dependency chain leading from package specified ' - 'in "--from" to package specified in "--to".', + _keyUpdateHashes, + help: 'Update the hashes of the pubspecs.', negatable: false, + // We don't want to promote usage, to not circumvent using this script to update + hide: !verboseHelp, ) - ..addOption( - 'from', + ..addMultiOption( + _keyCherryPick, help: - 'Used with "--dependency-path". Specifies the package to begin ' - 'searching dependency path from.', - ) - ..addOption( - 'to', - help: - 'Used with "--dependency-path". Specifies the package that the ' - 'sought-after dependency path leads to.', + 'Attempt to update only the specified package. To be specified as [pub package name]:[pub package version],[pub package2 name]:[pub package2 version].', ) ..addFlag( - 'transitive-closure', - help: - 'Prints the dependency graph that is the transitive closure of ' - 'packages the Flutter SDK depends on.', - negatable: false, - ) - ..addFlag( - 'consumer-only', - help: - 'Only prints the dependency graph that is the transitive closure ' - 'that a consumer of the Flutter SDK will observe (when combined ' - 'with "--transitive-closure").', + _keyOffline, + help: 'Use cached packages instead of accessing the network.', negatable: false, ) ..addFlag( - 'verify-only', - help: 'Verifies the package checksum without changing or updating deps.', - negatable: false, + _keyUpgradeMajor, + help: 'Upgrade major versions as well. Only makes sense with force-upgrade.', ) ..addFlag( - 'offline', - help: 'Use cached packages instead of accessing the network.', - negatable: false, + _keyExcludeTools, + help: "Don't update the deps in tools. For example when unpinning a dep.", ) ..addFlag( - 'crash', + _keyCrash, help: 'For Flutter CLI testing only, forces this command to throw an unhandled exception.', negatable: false, - ) - ..addOption( - 'jobs', - abbr: 'j', - help: - 'Causes the "pub get" runs to happen concurrently on this many ' - 'CPUs. Defaults to the number of CPUs that this machine has.', - ) - ..addOption( - 'synthetic-package-path', - help: - 'Write the synthetic monolithic pub package generated to do ' - 'version solving to a persistent path. By default, a temporary ' - 'directory that is deleted before the command exits. By ' - 'providing this path, a Flutter maintainer can inspect further ' - 'exactly how version solving was achieved.', + hide: !verboseHelp, ); } + final String _keyForceUpgrade = 'force-upgrade'; + final String _keyUpdateHashes = 'update-hashes'; + final String _keyCherryPick = 'cherry-pick'; + final String _keyOffline = 'offline'; + final String _keyUpgradeMajor = 'upgrade-major'; + final String _keyExcludeTools = 'exclude-tools'; + final String _keyCrash = 'crash'; + + static const Set fixedPackages = {'test_api', 'test_core'}; + @override final String name = 'update-packages'; @@ -156,35 +124,24 @@ class UpdatePackagesCommand extends FlutterCommand { ..writeAsBytesSync(data, flush: true); } - late final Directory _syntheticPackageDir = - (() { - final String? optionPath = stringArg('synthetic-package-path'); - if (optionPath == null) { - return globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.'); - } - final Directory syntheticPackageDir = globals.fs.directory(optionPath); - if (!syntheticPackageDir.existsSync()) { - syntheticPackageDir.createSync(recursive: true); - } - globals.printStatus( - 'The synthetic package with all pub dependencies across the repo will ' - 'be written to ${syntheticPackageDir.absolute.path}.', - ); - return syntheticPackageDir; - })(); - @override Future runCommand() async { - final List packages = runner!.getRepoPackages(); + // Add the root directory to the list of packages, to capture the workspace + // `pubspec.yaml`. + final Directory rootDirectory = globals.fs.directory( + globals.fs.path.absolute(Cache.flutterRoot!), + ); - final bool forceUpgrade = boolArg('force-upgrade'); - final bool isPrintPaths = boolArg('paths'); - final bool isPrintTransitiveClosure = boolArg('transitive-closure'); - final bool isVerifyOnly = boolArg('verify-only'); - final bool isConsumerOnly = boolArg('consumer-only'); - final bool offline = boolArg('offline'); - final String? cherryPickPackage = stringArg('cherry-pick-package'); - final String? cherryPickVersion = stringArg('cherry-pick-version'); + final bool forceUpgrade = boolArg(_keyForceUpgrade); + final bool updateHashes = boolArg(_keyUpdateHashes); + final bool offline = boolArg(_keyOffline); + final List cherryPicks = + stringsArg(_keyCherryPick) + .map((String e) => e.split(':')) + .map((List e) => (package: e[0], version: e[1])) + .toList(); + final bool relaxToAny = boolArg(_keyUpgradeMajor); + final bool excludeTools = boolArg(_keyExcludeTools); if (boolArg('crash')) { throw StateError('test crash please ignore.'); @@ -194,64 +151,14 @@ class UpdatePackagesCommand extends FlutterCommand { throwToolExit('--force-upgrade cannot be used with the --offline flag'); } - if (forceUpgrade && cherryPickPackage != null) { + if (forceUpgrade && cherryPicks.isNotEmpty) { throwToolExit('--force-upgrade cannot be used with the --cherry-pick-package flag'); } - if (forceUpgrade && isPrintPaths) { - throwToolExit('--force-upgrade cannot be used with the --paths flag'); - } - - if (forceUpgrade && isPrintTransitiveClosure) { - throwToolExit('--force-upgrade cannot be used with the --transitive-closure flag'); - } - - if (cherryPickPackage != null && offline) { + if (cherryPicks.isNotEmpty && offline) { throwToolExit('--cherry-pick-package cannot be used with the --offline flag'); } - if (cherryPickPackage != null && cherryPickVersion == null) { - throwToolExit('--cherry-pick-version is required when using --cherry-pick-package flag'); - } - - if (isPrintPaths && (stringArg('from') == null || stringArg('to') == null)) { - throwToolExit('The --from and --to flags are required when using the --paths flag'); - } - - if (!isPrintPaths && (stringArg('from') != null || stringArg('to') != null)) { - throwToolExit('The --from and --to flags are only allowed when using the --paths flag'); - } - - if (isPrintTransitiveClosure && isPrintPaths) { - throwToolExit('The --transitive-closure flag cannot be used with the --paths flag'); - } - - // "consumer" packages are those that constitute our public API (e.g. flutter, flutter_test, flutter_driver, flutter_localizations, integration_test). - if (isConsumerOnly) { - if (!isPrintTransitiveClosure) { - throwToolExit('--consumer-only can only be used with the --transitive-closure flag'); - } - // Only retain flutter, flutter_test, flutter_driver, and flutter_localizations. - const List consumerPackages = [ - 'flutter', - 'flutter_test', - 'flutter_driver', - 'flutter_localizations', - 'integration_test', - ]; - // ensure we only get flutter/packages - packages.retainWhere((Directory directory) { - return consumerPackages.any((String package) { - return directory.path.endsWith('packages${globals.fs.path.separator}$package'); - }); - }); - } - - if (isVerifyOnly) { - _verifyPubspecs(packages); - return FlutterCommandResult.success(); - } - if (forceUpgrade) { // This feature attempts to collect all the packages used across all the // pubspec.yamls in the repo (including via transitive dependencies), and @@ -259,1548 +166,391 @@ class UpdatePackagesCommand extends FlutterCommand { // such package fixed at a single version across all the pubspec.yamls. globals.printStatus('Upgrading packages...'); } - - // First, collect the dependencies: - final List pubspecs = []; - final Map explicitDependencies = {}; - final Map allDependencies = {}; - final Set specialDependencies = {}; - _collectDependencies( - packages: packages, - pubspecs: pubspecs, - explicitDependencies: explicitDependencies, - allDependencies: allDependencies, - specialDependencies: specialDependencies, - printPaths: - forceUpgrade || isPrintPaths || isPrintTransitiveClosure || cherryPickPackage != null, + final FlutterProject rootProject = FlutterProject.fromDirectory(rootDirectory); + final FlutterProject toolProject = FlutterProject.fromDirectory( + rootDirectory.childDirectory('packages').childDirectory('flutter_tools'), ); - - final Iterable baseDependencies; - if (cherryPickPackage != null) { - if (!allDependencies.containsKey(cherryPickPackage)) { - throwToolExit( - 'Package "$cherryPickPackage" is not currently a dependency, and therefore cannot be upgraded.', - ); - } - if (cherryPickVersion != null) { - globals.printStatus( - 'Pinning package "$cherryPickPackage" to version "$cherryPickVersion"...', - ); - } else { - globals.printStatus('Upgrading package "$cherryPickPackage"...'); - } - final List adjustedDependencies = []; - for (final String package in allDependencies.keys) { - if (package == cherryPickPackage) { - assert(cherryPickVersion != null); - final PubspecDependency pubspec = allDependencies[cherryPickPackage]!; - adjustedDependencies.add(pubspec.copyWith(version: cherryPickVersion)); - } else { - adjustedDependencies.add(allDependencies[package]!); - } - } - baseDependencies = adjustedDependencies; - } else if (forceUpgrade) { - baseDependencies = explicitDependencies.values; - } else { - baseDependencies = allDependencies.values; - } - - // Now that we have all the dependencies we care about, we are going to - // create a fake package and then run either "pub upgrade", if requested, - // followed by "pub get" on it. If upgrading, the pub tool will attempt to - // bring these dependencies up to the most recent possible versions while - // honoring all their constraints. If not upgrading the pub tool will only - // attempt to download any necessary package versions to the pub cache to - // warm the cache. - final PubDependencyTree tree = PubDependencyTree(); // object to collect results - await _pubGetAllDependencies( - tempDir: _syntheticPackageDir, - dependencies: baseDependencies, - pubspecs: pubspecs, - tree: tree, - doUpgrade: forceUpgrade, - isolateEnvironment: - forceUpgrade || isPrintPaths || isPrintTransitiveClosure || cherryPickPackage != null, - reportDependenciesToTree: - forceUpgrade || isPrintPaths || isPrintTransitiveClosure || cherryPickPackage != null, + // This needs to be special cased, as it is below flutter_tools, so cannot + // be in the flutter pub workspace. + final FlutterProject widgetPreviewScaffoldProject = FlutterProject.fromDirectory( + rootProject.directory + .childDirectory('packages') + .childDirectory('flutter_tools') + .childDirectory('test') + .childDirectory('widget_preview_scaffold.shard') + .childDirectory('widget_preview_scaffold'), ); + final List packages = [...runner!.getRepoPackages(), rootDirectory]; - // Only delete the synthetic package if it was done in a temp directory - if (stringArg('synthetic-package-path') == null) { - _syntheticPackageDir.deleteSync(recursive: true); - } - - if (forceUpgrade || isPrintTransitiveClosure || isPrintPaths || cherryPickPackage != null) { - _processPubspecs(tree: tree, pubspecs: pubspecs, specialDependencies: specialDependencies); - - if (isPrintTransitiveClosure) { - tree._dependencyTree.forEach((String from, Set to) { - globals.printStatus('$from -> $to'); - }); - return FlutterCommandResult.success(); - } - - if (isPrintPaths) { - showDependencyPaths(from: stringArg('from')!, to: stringArg('to')!, tree: tree); - return FlutterCommandResult.success(); - } - - globals.printStatus('Updating workspace...'); - _updatePubspecs(tree: tree, pubspecs: pubspecs, specialDependencies: specialDependencies); + if (!updateHashes) { + _verifyPubspecs(packages); } - - await _runPubGetOnPackages(packages); - - return FlutterCommandResult.success(); - } - - void _verifyPubspecs(List packages) { - bool needsUpdate = false; - globals.printStatus('Verifying pubspecs...'); - for (final Directory directory in packages) { - final PubspecYaml pubspec = PubspecYaml(directory); - globals.printTrace('Reading pubspec.yaml from ${directory.path}'); - if (pubspec.checksum.value == null) { - // If the checksum is invalid or missing, we can just ask them run to run - // upgrade again to compute it. - globals.printWarning( - 'Warning: pubspec in ${directory.path} has out of date dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly.', - ); - needsUpdate = true; - } - // all dependencies in the pubspec sorted lexically. - final Map checksumDependencies = {}; - for (final PubspecLine data in pubspec.inputData) { - if (data is PubspecDependency && data.kind == DependencyKind.normal) { - checksumDependencies[data.name] = data.version; - } - } - final String checksum = _computeChecksum( - checksumDependencies.keys, - (String name) => checksumDependencies[name]!, - ); - if (checksum != pubspec.checksum.value) { - // If the checksum doesn't match, they may have added or removed some dependencies. - // we need to run update-packages to recapture the transitive deps. - globals.printWarning( - 'Warning: pubspec in ${directory.path} has updated or new dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly.', - // DO NOT PRINT THE CHECKSUM HERE. - // It causes people to ignore the requirement to actually run the script. + if (forceUpgrade || cherryPicks.isNotEmpty) { + if (!excludeTools) { + final ResolvedDependencies toolDeps = await _upgrade( + forceUpgrade, + cherryPicks, + toolProject, + relaxToAny, ); - needsUpdate = true; - } else { - // everything is correct in the pubspec. - globals.printTrace('pubspec in ${directory.path} is up to date!'); + _updatePubspec(toolProject.directory, toolDeps); } - } - if (needsUpdate) { - throwToolExit( - 'Warning: one or more pubspecs have invalid dependencies. ' - 'Please run "flutter update-packages --force-upgrade" to update them correctly.', - exitCode: 1, + + final ResolvedDependencies deps = await _upgrade( + forceUpgrade, + cherryPicks, + rootProject, + relaxToAny, ); - } - globals.printStatus('All pubspecs were up to date.'); - } - void _collectDependencies({ - required List packages, - required List pubspecs, - required Set specialDependencies, - required Map explicitDependencies, - required Map allDependencies, - required bool printPaths, - }) { - // Visit all the directories with pubspec.yamls we care about. - for (final Directory directory in packages) { - if (printPaths) { - globals.printTrace('Reading pubspec.yaml from: ${directory.path}'); - } - final PubspecYaml pubspec = PubspecYaml(directory); // this parses the pubspec.yaml - pubspecs.add(pubspec); // remember it for later - for (final PubspecDependency dependency in pubspec.allDependencies) { - if (allDependencies.containsKey(dependency.name)) { - // If we've seen the dependency before, make sure that we are - // importing it the same way. There's several ways to import a - // dependency. Hosted (from pub via version number), by path (e.g. - // pointing at the version of a package we get from the Dart SDK - // that we download with Flutter), by SDK (e.g. the "flutter" - // package is explicitly from "sdk: flutter"). - // - // This makes sure that we don't import a package in two different - // ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and - // saying "path: ../../..." in another. - final PubspecDependency previous = allDependencies[dependency.name]!; - if (dependency.kind != previous.kind || dependency._lockTarget != previous._lockTarget) { - throwToolExit( - 'Inconsistent requirements around ${dependency.name}; ' - 'saw ${dependency.kind} (${dependency._lockTarget}) in "${dependency.sourcePath}" ' - 'and ${previous.kind} (${previous._lockTarget}) in "${previous.sourcePath}".', - ); - } - if (dependency.version != previous.version) { - globals.printError( - 'Requiring multiple versions: multiple versions required by ${dependency.name}; ' - 'saw ${dependency.version} in "${dependency.sourcePath}" ' - 'and ${previous.version} in "${previous.sourcePath}".', - ); - } - } - allDependencies[dependency.name] = dependency; - } - for (final PubspecDependency dependency in pubspec.allExplicitDependencies) { - if (explicitDependencies.containsKey(dependency.name)) { - // If we've seen the dependency before, make sure that we are - // importing it the same way. There's several ways to import a - // dependency. Hosted (from pub via version number), by path (e.g. - // pointing at the version of a package we get from the Dart SDK - // that we download with Flutter), by SDK (e.g. the "flutter" - // package is explicitly from "sdk: flutter"). - // - // This makes sure that we don't import a package in two different - // ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and - // saying "path: ../../..." in another. - final PubspecDependency previous = explicitDependencies[dependency.name]!; - if (dependency.kind != previous.kind || dependency._lockTarget != previous._lockTarget) { - throwToolExit( - 'Inconsistent requirements around ${dependency.name}; ' - 'saw ${dependency.kind} (${dependency._lockTarget}) in "${dependency.sourcePath}" ' - 'and ${previous.kind} (${previous._lockTarget}) in "${previous.sourcePath}".', - ); - } - } - // Remember this dependency by name so we can look it up again. - explicitDependencies[dependency.name] = dependency; - // Normal dependencies are those we get from pub. The others we - // already implicitly pin since we pull down one version of the - // Flutter and Dart SDKs, so we track which those are here so that we - // can omit them from our list of pinned dependencies later. - if (dependency.kind != DependencyKind.normal) { - specialDependencies.add(dependency.name); - } + for (final Directory package in [ + rootDirectory, + rootDirectory.childDirectory('packages').childDirectory('flutter'), + rootDirectory.childDirectory('packages').childDirectory('flutter_test'), + rootDirectory.childDirectory('packages').childDirectory('flutter_localizations'), + widgetPreviewScaffoldProject.directory, + ]) { + _updatePubspec(package, deps); } } - } - - Future _pubGetAllDependencies({ - required Directory tempDir, - required Iterable dependencies, - required List pubspecs, - required PubDependencyTree tree, - required bool doUpgrade, - required bool isolateEnvironment, - required bool reportDependenciesToTree, - }) async { - Directory? temporaryFlutterSdk; - final Directory syntheticPackageDir = tempDir.childDirectory('synthetic_package'); - final File fakePackage = _pubspecFor(syntheticPackageDir); - fakePackage.createSync(recursive: true); - fakePackage.writeAsStringSync(generateFakePubspec(dependencies, doUpgrade: doUpgrade)); - - if (isolateEnvironment) { - // Create a synthetic flutter SDK so that transitive flutter SDK - // constraints are not affected by this upgrade. - temporaryFlutterSdk = createTemporaryFlutterSdk( - globals.logger, - globals.fs, - globals.fs.directory(Cache.flutterRoot), - pubspecs, - tempDir, - ); + globals.printStatus('Running pub get only...'); + if (updateHashes || forceUpgrade || cherryPicks.isNotEmpty) { + _writeHashesToPubspecs(packages); } + _verifyPubspecs(packages); + _checkWithFlutterTools(rootDirectory); + _checkPins(rootDirectory); - // Run "pub get" on it in order to force the download of any - // needed packages to the pub cache, upgrading if requested. - await pub.get( - context: PubContext.updatePackages, - project: FlutterProject.fromDirectory(syntheticPackageDir), - upgrade: doUpgrade, - offline: boolArg('offline'), - flutterRootOverride: temporaryFlutterSdk?.path, - outputMode: PubOutputMode.failuresOnly, + await _pubGet(rootProject, !forceUpgrade && cherryPicks.isEmpty && !updateHashes); + await _pubGet(toolProject, !forceUpgrade && cherryPicks.isEmpty && !updateHashes); + await _pubGet( + widgetPreviewScaffoldProject, + !forceUpgrade && cherryPicks.isEmpty && !updateHashes, ); - if (reportDependenciesToTree) { - // Run "pub deps --style=compact" on the result. - // We pipe all the output to tree.fill(), which parses it so that it can - // create a graph of all the dependencies so that we can figure out the - // transitive dependencies later. It also remembers which version was - // selected for each package. - await pub.batch( - ['deps', '--style=compact'], - context: PubContext.updatePackages, - directory: syntheticPackageDir.path, - filter: tree.fill, - ); - } - } - - void _processPubspecs({ - required PubDependencyTree tree, - required List pubspecs, - required Set specialDependencies, - }) { - for (final PubspecYaml pubspec in pubspecs) { - final String package = pubspec.name; - specialDependencies.add(package); - tree._versions[package] = pubspec.version; - for (final PubspecDependency dependency in pubspec.dependencies) { - if (dependency.kind == DependencyKind.normal) { - tree._dependencyTree[package] ??= {}; - tree._dependencyTree[package]!.add(dependency.name); - } - } - } - } + await _downloadCoverageData(); - bool _updatePubspecs({ - required PubDependencyTree tree, - required List pubspecs, - required Set specialDependencies, - }) { - // Now that we have collected all the data, we can apply our dependency - // versions to each pubspec.yaml that we collected. This mutates the - // pubspec.yaml files. - // - // The specialDependencies argument is the set of package names to not pin - // to specific versions because they are explicitly pinned by their - // constraints. Here we list the names we earlier established we didn't - // need to pin because they come from the Dart or Flutter SDKs. - for (final PubspecYaml pubspec in pubspecs) { - pubspec.apply(tree, specialDependencies); - } - return false; + return FlutterCommandResult.success(); } - Future _runPubGetOnPackages(List packages) async { - final Stopwatch timer = Stopwatch()..start(); - int count = 0; + Future _pubGet(FlutterProject project, bool enforceLockfile) async => + pub.get(context: PubContext.pubGet, project: project, enforceLockfile: enforceLockfile); - // Now we run pub get on each of the affected packages to update their - // pubspec.lock files with the right transitive dependencies. - // - // This can be expensive, so we run them in parallel. If we hadn't already - // warmed the cache above, running them in parallel could be dangerous due - // to contention when unpacking downloaded dependencies, but since we have - // downloaded all that we need, it is safe to run them in parallel. - final Status status = globals.logger.startProgress( - 'Running "flutter pub get" in affected packages...', - ); - try { - // int.tryParse will not accept null, but will convert empty string to null - final int? maxJobs = int.tryParse(stringArg('jobs') ?? ''); - final TaskQueue queue = TaskQueue(maxJobs: maxJobs); - for (final Directory dir in packages) { - unawaited( - queue.add(() async { - final Stopwatch stopwatch = Stopwatch(); - stopwatch.start(); - await pub.get( - context: PubContext.updatePackages, - project: FlutterProject.fromDirectory(dir), - // All dependencies should already have been downloaded by the fake - // package, so the concurrent checks can all happen offline. - offline: true, - outputMode: PubOutputMode.failuresOnly, - ); - stopwatch.stop(); - final double seconds = stopwatch.elapsedMilliseconds / 1000.0; - final String relativeDir = globals.fs.path.relative(dir.path, from: Cache.flutterRoot); - globals.printStatus('Ran pub get in $relativeDir in ${seconds.toStringAsFixed(1)}s...'); - }), - ); - count += 1; - } - unawaited( - queue.add(() async { - final Stopwatch stopwatch = Stopwatch(); - await _downloadCoverageData(); - stopwatch.stop(); - final double seconds = stopwatch.elapsedMilliseconds / 1000.0; - globals.printStatus( - 'Downloaded lcov data for package:flutter in ${seconds.toStringAsFixed(1)}s...', - ); - }), - ); - await queue.tasksComplete; - status.stop(); - // The exception is rethrown, so don't catch only Exceptions. - } catch (exception) { - status.cancel(); - rethrow; + Future _upgrade( + bool forceUpgrade, + List cherryPicks, + FlutterProject project, + bool relaxToAny, + ) async { + final Map pinnedDeps; + if (forceUpgrade) { + globals.printStatus('Upgrading packages versions...'); + pinnedDeps = kManuallyPinnedDependencies; + } else if (cherryPicks.isNotEmpty) { + globals.printStatus('Pinning packages "$cherryPicks"...'); + pinnedDeps = { + for (final CherryPick cherryPick in cherryPicks) cherryPick.package: cherryPick.version, + }; + } else { + throw StateError('To get here, either forceUpgrade or cherry pick should be set.'); } - final double seconds = timer.elapsedMilliseconds / 1000.0; - globals.printStatus( - "\nRan 'pub get' $count time${count == 1 ? "" : "s"} and fetched coverage data in ${seconds.toStringAsFixed(1)}s.", + final Directory tempDir = globals.fs.systemTempDirectory.createTempSync( + 'flutter_upgrade_packages.', ); - } - - void showDependencyPaths({ - required String from, - required String to, - required PubDependencyTree tree, - }) { - if (!tree.contains(from)) { - throwToolExit('Package $from not found in the dependency tree.'); - } - if (!tree.contains(to)) { - throwToolExit('Package $to not found in the dependency tree.'); - } + final File tempPubspec = tempDir.childFile(_pubspecName)..createSync(); + globals.printStatus('Writing to temp pubspec at $tempPubspec'); + final String pubspecContents = project.pubspecFile.readAsStringSync(); + final YamlEditor yamlEditor = YamlEditor(pubspecContents); + final ResolvedDependencies oldDeps = _fetchDeps(yamlEditor); - final Queue<_DependencyLink> traversalQueue = Queue<_DependencyLink>(); - final Set visited = {}; - final List<_DependencyLink> paths = <_DependencyLink>[]; - - traversalQueue.addFirst(_DependencyLink(from: null, to: from)); - while (traversalQueue.isNotEmpty) { - final _DependencyLink link = traversalQueue.removeLast(); - if (link.to == to) { - paths.add(link); - } - if (link.from != null) { - visited.add(link.from!.to); - } - for (final String dependency in tree._dependencyTree[link.to]!) { - if (!visited.contains(dependency)) { - traversalQueue.addFirst(_DependencyLink(from: link, to: dependency)); - } - } + final List workspacePath = ['workspace']; + if (yamlEditor.parseAt(workspacePath, orElse: () => wrapAsYamlNode(null)).value != null) { + yamlEditor.remove(workspacePath); } - for (_DependencyLink? path in paths) { - final StringBuffer buf = StringBuffer(); - while (path != null) { - buf.write(path.to); - path = path.from; - if (path != null) { - buf.write(' <- '); - } - } - globals.printStatus(buf.toString(), wrap: false); - } - - if (paths.isEmpty) { - globals.printStatus('No paths found from $from to $to'); - } - } -} - -class _DependencyLink { - _DependencyLink({required this.from, required this.to}); - - final _DependencyLink? from; - final String to; - - @override - String toString() => '${from?.to} -> $to'; -} - -/// The various sections of a pubspec.yaml file. -/// -/// We care about the "dependencies", "dev_dependencies", and -/// "dependency_overrides" sections, as well as the "name" and "version" fields -/// in the pubspec header bucketed into [header]. The others are all bucketed -/// into [other]. -enum Section { header, dependencies, devDependencies, dependencyOverrides, builders, other } - -/// The various kinds of dependencies we know and care about. -enum DependencyKind { - // Dependencies that will be path or sdk dependencies but - // for which we haven't yet parsed the data. - unknown, - - // Regular dependencies with a specified version range. - normal, - - // Dependency that uses an explicit path, e.g. into the Dart SDK. - path, - - // Dependency defined as coming from an SDK (typically "sdk: flutter"). - sdk, - - // A dependency that was "normal", but for which we later found a "path" or - // "sdk" dependency in the dependency_overrides section. - overridden, - - // A dependency that uses git. - git, -} - -/// This is the string we output next to each of our autogenerated transitive -/// dependencies so that we can ignore them the next time we parse the -/// pubspec.yaml file. -const String kTransitiveMagicString = - '# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"'; - -/// This is the string output before a checksum of the packages used. -const String kDependencyChecksum = '# PUBSPEC CHECKSUM: '; - -/// This class represents a pubspec.yaml file for the purposes of upgrading the -/// dependencies as done by this file. -class PubspecYaml { - /// You create one of these by providing a directory, from which we obtain the - /// pubspec.yaml and parse it into a line-by-line form. - factory PubspecYaml(Directory directory) { - final File file = _pubspecFor(directory); - return _parse(file, file.readAsLinesSync()); - } - - PubspecYaml._(this.file, this.name, this.version, this.inputData, this.checksum); - - final File file; // The actual pubspec.yaml file. - - /// The package name. - final String name; - - /// The package version. - final String? version; + final RelaxMode relaxMode = switch (cherryPicks.isNotEmpty) { + true => RelaxMode.strict, + false => relaxToAny ? RelaxMode.any : RelaxMode.caret, + }; + _relaxDeps(yamlEditor, relaxMode, pinnedDeps); - final List inputData; // Each line of the pubspec.yaml file, parsed(ish). + tempPubspec.writeAsStringSync(yamlEditor.toString()); - /// The package checksum. - /// - /// If this was not found in the pubspec, a synthetic checksum is created - /// with a value of `-1`. - final PubspecChecksum checksum; + globals.printStatus('Upgrade in $tempDir'); + await pub.interactively( + ['upgrade', '--tighten', '-C', tempDir.path], + context: PubContext.updatePackages, + project: FlutterProject.fromDirectory(tempDir), + command: 'update', + ); - /// This parses each line of a pubspec.yaml file (a list of lines) into - /// slightly more structured data (in the form of a list of PubspecLine - /// objects). We don't just use a YAML parser because we care about comments - /// and also because we can just define the style of pubspec.yaml files we care - /// about (since they're all under our control). - static PubspecYaml _parse(File file, List lines) { - final String filename = file.path; - String? packageName; - String? packageVersion; - PubspecChecksum? - checksum; // the checksum value used to verify that dependencies haven't changed. - final List result = []; // The output buffer. - Section section = Section.other; // Which section we're currently reading from. - bool seenMain = false; // Whether we've seen the "dependencies:" section. - bool seenDev = false; // Whether we've seen the "dev_dependencies:" section. - // The masterDependencies map is used to keep track of the objects - // representing actual dependencies we've seen so far in this file so that - // if we see dependency overrides we can update the actual dependency so it - // knows that it's not really a dependency. - final Map masterDependencies = {}; - // The "special" dependencies (the ones that use git: or path: or sdk: or - // whatnot) have the style of having extra data after the line that declares - // the dependency. So we track what is the "current" (or "last") dependency - // that we are dealing with using this variable. - PubspecDependency? lastDependency; - for (int index = 0; index < lines.length; index += 1) { - String line = lines[index]; - if (lastDependency == null) { - // First we look to see if we're transitioning to a new top-level section. - // The PubspecHeader.parse static method can recognize those headers. - final PubspecHeader? header = PubspecHeader.parse(line); // See if it's a header. - if (header != null) { - // It is! - section = header.section; // The parser determined what kind of section it is. - if (section == Section.header) { - if (header.name == 'name') { - packageName = header.value; - } else if (header.name == 'version') { - packageVersion = header.value; - } - } else if (section == Section.dependencies) { - // If we're entering the "dependencies" section, we want to make sure that - // it's the first section (of those we care about) that we've seen so far. - if (seenMain) { - throwToolExit( - 'Two dependencies sections found in $filename. There should only be one.', - ); - } - if (seenDev) { - throwToolExit( - 'The dependencies section was after the dev_dependencies section in $filename. ' - 'To enable one-pass processing, the dependencies section must come before the ' - 'dev_dependencies section.', - ); - } - seenMain = true; - } else if (section == Section.devDependencies) { - // Similarly, if we're entering the dev_dependencies section, we should verify - // that we've not seen one already. - if (seenDev) { - throwToolExit( - 'Two dev_dependencies sections found in $filename. There should only be one.', - ); - } - seenDev = true; - } - result.add(header); - } else if (section == Section.builders) { - // Do nothing. - // This line isn't a section header, and we're not in a section we care about. - // We just stick the line into the output unmodified. - result.add(PubspecLine(line)); - } else if (section == Section.other) { - if (line.contains(kDependencyChecksum)) { - // This is the pubspec checksum. After computing it, we remove it from the output data - // since it will be recomputed later. - checksum = PubspecChecksum.parse(line); - } else { - // This line isn't a section header, and we're not in a section we care about. - // We just stick the line into the output unmodified. - result.add(PubspecLine(line)); - } - } else { - // We're in a section we care about. Try to parse out the dependency: - final PubspecDependency? dependency = PubspecDependency.parse( - line, - filename: filename, - isDevDependency: seenDev, - ); - if (dependency != null) { - // We got one! - result.add(dependency); - if (dependency.kind == DependencyKind.unknown) { - // If we didn't get a version number, then we need to be ready to - // read the next line as part of this dependency, so keep track of - // this dependency object. - lastDependency = dependency; - } - if (section != Section.dependencyOverrides) { - // If we're not in the overrides section, then just remember the - // dependency, in case it comes up again later in the overrides - // section. - // - // First, make sure it's a unique dependency. Listing dependencies - // twice doesn't make sense. - if (masterDependencies.containsKey(dependency.name)) { - throwToolExit('$filename contains two dependencies on ${dependency.name}.'); - } - masterDependencies[dependency.name] = dependency; - } else { - // If we _are_ in the overrides section, then go tell the version - // we saw earlier (if any -- there might not be, we might be - // overriding a transitive dependency) that we have overridden it, - // so that later when we output the dependencies we can leave - // the line unmodified. - masterDependencies[dependency.name]?.markOverridden(dependency); - } - } else if (line.contains(kDependencyChecksum)) { - // This is the pubspec checksum. After computing it, we remove it from the output data - // since it will be recomputed later. - checksum = PubspecChecksum.parse(line); + final ResolvedDependencies newDeps = _fetchDeps(YamlEditor(tempPubspec.readAsStringSync())); + + final ResolvedDependencies deps = ResolvedDependencies.mergeDeps(oldDeps, newDeps, cherryPicks); + tempDir.deleteSync(recursive: true); + return deps; + } + + void _relaxDeps(YamlEditor yamlEditor, RelaxMode relaxMode, Map fixedDeps) { + ResolvedDependencies().forEach( + yamlEditor: yamlEditor, + func: ( + Map dependencies, + String depType, + String packageName, + Object? version, + ) { + if (version is String) { + if (fixedDeps.containsKey(packageName)) { + yamlEditor.update([depType, packageName], fixedDeps[packageName]); } else { - // We're in a section we care about but got a line we didn't - // recognize. Maybe it's a comment or a blank line or something. - // Just pass it through. - result.add(PubspecLine(line)); + yamlEditor.update( + [depType, packageName], + switch (relaxMode) { + RelaxMode.any => 'any', + RelaxMode.caret => _versionWithCaret(version), + RelaxMode.strict => _versionWithoutCaret(version), + }, + ); } } - } else { - // If we're here it means the last line was a dependency that needed - // extra information to be parsed from the next line. - // - // Try to parse the line by giving it to the last PubspecDependency - // object we created. If parseLock fails to recognize the line, it will - // throw. If it does recognize the line and needs the following lines in - // its lockLine, it'll return false. - // Otherwise it returns true. - // - // If it returns true, then it will have updated itself internally to - // store the information from this line. - if (!lastDependency.parseLock( - line, - filename, - lockIsOverride: section == Section.dependencyOverrides, - )) { - // Ok we're dealing with some "git:" dependency. Consume lines until - // we are out of the git dependency, and stuff them into the lock - // line. - lastDependency._lockLine = line; - lastDependency._lockIsOverride = section == Section.dependencyOverrides; - do { - index += 1; - if (index == lines.length) { - throw StateError( - 'Invalid pubspec.yaml: a "git" dependency section terminated early.', - ); - } - line = lines[index]; - lastDependency._lockLine = '${lastDependency._lockLine}\n$line'; - } while (line.startsWith(' ')); - } - // We're done with this special dependency, so reset back to null so - // we'll go in the top section next time instead. - lastDependency = null; - } - } - return PubspecYaml._( - file, - packageName!, - packageVersion, - result, - checksum ?? PubspecChecksum(null, ''), + }, ); } - /// This returns all the explicit dependencies that this pubspec.yaml lists under dependencies. - Iterable get dependencies { - // It works by iterating over the parsed data from _parse above, collecting - // all the dependencies that were found, ignoring any that are flagged as as - // overridden by subsequent entries in the same file and any that have the - // magic comment flagging them as auto-generated transitive dependencies - // that we added in a previous run. - return inputData.whereType().where( - (PubspecDependency data) => - data.kind != DependencyKind.overridden && !data.isTransitive && !data.isDevDependency, + ResolvedDependencies _fetchDeps(YamlEditor yamlEditor) { + return ResolvedDependencies()..forEach( + yamlEditor: yamlEditor, + func: ( + Map dependencies, + String depType, + String packageName, + Object? version, + ) { + if (version is String) { + dependencies[packageName] = version; + } + }, ); } - /// This returns all regular dependencies and all dev dependencies. - Iterable get allExplicitDependencies { - return inputData.whereType().where( - (PubspecDependency data) => data.kind != DependencyKind.overridden && !data.isTransitive, + void _updatePubspec(Directory package, ResolvedDependencies dependencies) { + final File pubspecFile = package.childFile(_pubspecName); + final YamlEditor yamlEditor = YamlEditor(pubspecFile.readAsStringSync()); + dependencies.forEach( + yamlEditor: yamlEditor, + func: ( + Map dependencies, + String depType, + String packageName, + Object? version, + ) { + if (dependencies.containsKey(packageName)) { + final String version = dependencies[packageName]!; + yamlEditor.update([depType, packageName], version); + } + }, ); + pubspecFile.writeAsStringSync(yamlEditor.toString()); } - /// This returns all dependencies. - Iterable get allDependencies { - return inputData.whereType(); + void _verifyPubspecs(List packages) { + globals.printStatus('Verifying pubspecs...'); + for (final Directory directory in packages) { + globals.printTrace('Reading pubspec.yaml from ${directory.path}'); + final String pubspecString = directory.childFile(_pubspecName).readAsStringSync(); + _checkHash(pubspecString, directory); + } } - /// Take a dependency graph with explicit version numbers, and apply them to - /// the pubspec.yaml, ignoring any that we know are special dependencies (those - /// that depend on the Flutter or Dart SDK directly and are thus automatically - /// pinned). - void apply(PubDependencyTree versions, Set specialDependencies) { - final List output = []; // the string data to output to the file, line by line - final Set directDependencies = - {}; // packages this pubspec directly depends on (i.e. not transitive) - final Set devDependencies = {}; - Section section = Section.other; // the section we're currently handling - - // the line number where we're going to insert the transitive dependencies. - int? endOfDirectDependencies; - // The line number where we're going to insert the transitive dev dependencies. - int? endOfDevDependencies; - // Walk the pre-parsed input file, outputting it unmodified except for - // updating version numbers, removing the old transitive dependencies lines, - // and adding our new transitive dependencies lines. We also do a little - // cleanup, removing trailing spaces, removing double-blank lines, leading - // blank lines, and trailing blank lines, and ensuring the file ends with a - // newline. This cleanup lets us be a little more aggressive while building - // the output. - for (final PubspecLine data in inputData) { - if (data is PubspecHeader) { - // This line was a header of some sort. - // - // If we're leaving one of the sections in which we can list transitive - // dependencies, then remember this as the current last known valid - // place to insert our transitive dependencies. - if (section == Section.dependencies) { - endOfDirectDependencies = output.length; - } - if (section == Section.devDependencies) { - endOfDevDependencies = output.length; - } - section = data.section; // track which section we're now in. - output.add(data.line); // insert the header into the output - } else if (data is PubspecDependency) { - // This was a dependency of some sort. - // How we handle this depends on the section. - switch (section) { - case Section.devDependencies: - case Section.dependencies: - // For the dependencies and dev_dependencies sections, we reinsert - // the dependency if it wasn't one of our autogenerated transitive - // dependency lines. - if (!data.isTransitive) { - // Assert that we haven't seen it in this file already. - assert( - !directDependencies.contains(data.name) && !devDependencies.contains(data.name), - ); - if (data.kind == DependencyKind.normal) { - // This is a regular dependency, so we need to update the - // version number. - // - // We output data that matches the format that - // PubspecDependency.parse can handle. The data.suffix is any - // previously-specified trailing comment. - assert(versions.contains(data.name), "versions doesn't contain ${data.name}"); - output.add(' ${data.name}: ${versions.versionFor(data.name)}${data.suffix}'); - } else { - // If it wasn't a regular dependency, then we output the line - // unmodified. If there was an additional line (e.g. an "sdk: - // flutter" line) then we output that too. - output.add(data.line); - if (data.lockLine != null) { - output.add(data.lockLine!); - } - } - // Remember that we've dealt with this dependency so we don't - // mention it again when doing the transitive dependencies. - if (section == Section.dependencies) { - directDependencies.add(data.name); - } else { - devDependencies.add(data.name); - } - } - // Since we're in one of the places where we can list dependencies, - // remember this as the current last known valid place to insert our - // transitive dev dependencies. If the section is for regular dependencies, - // then also remember the line for the end of direct dependencies. - if (section == Section.dependencies) { - endOfDirectDependencies = output.length; - } - endOfDevDependencies = output.length; - case Section.builders: - case Section.dependencyOverrides: - case Section.header: - case Section.other: - // In other sections, pass everything through in its original form. - output.add(data.line); - if (data.lockLine != null) { - output.add(data.lockLine!); - } - } - } else { - // Not a header, not a dependency, just pass that through unmodified. - output.add(data.line); + void _checkWithFlutterTools(Directory rootDirectory) { + final Pubspec pubspec = Pubspec.parse(rootDirectory.childFile(_pubspecName).readAsStringSync()); + final Pubspec pubspecTools = Pubspec.parse( + rootDirectory + .childDirectory('packages') + .childDirectory('flutter_tools') + .childFile(_pubspecName) + .readAsStringSync(), + ); + for (final String package in fixedPackages) { + if (!(pubspec.dependencies[package] == pubspecTools.dependencies[package] && + pubspec.devDependencies[package] == pubspecTools.devDependencies[package] && + pubspec.dependencyOverrides[package] == pubspecTools.dependencyOverrides[package])) { + throwToolExit('The dependency on $package must be fixed between flutter and flutter_tools'); } } + } - // If there are no dependencies or dev_dependencies sections, these will be - // null. We have such files in our tests, so account for them here. - endOfDirectDependencies ??= output.length; - endOfDevDependencies ??= output.length; - - // Now include all the transitive dependencies and transitive dev dependencies. - // The blocks of text to insert for each dependency section. - final List transitiveDependencyOutput = []; - final List transitiveDevDependencyOutput = []; - - // Which dependencies we need to handle for the transitive and dev dependency sections. - final Set transitiveDependencies = {}; - final Set transitiveDevDependencies = {}; - - // Merge the lists of dependencies we've seen in this file from dependencies, dev dependencies, - // and the dependencies we know this file mentions that are already pinned - // (and which didn't get special processing above). - final Set implied = { - ...directDependencies, - ...specialDependencies, - ...devDependencies, - ...kExplicitlyExcludedPackages, - }; - - // Create a new set to hold the list of packages we've already processed, so - // that we don't redundantly process them multiple times. - final Set done = {}; - for (final String package in directDependencies) { - transitiveDependencies.addAll( - versions.getTransitiveDependenciesFor(package, seen: done, exclude: implied), - ); - } - for (final String package in devDependencies) { - transitiveDevDependencies.addAll( - versions.getTransitiveDependenciesFor(package, seen: done, exclude: implied), - ); - } - - // Sort each dependency block lexically so that we don't get noisy diffs when upgrading. - final List transitiveDependenciesAsList = transitiveDependencies.toList()..sort(); - final List transitiveDevDependenciesAsList = transitiveDevDependencies.toList()..sort(); - - String computeTransitiveDependencyLineFor(String package) { - return ' $package: ${versions.versionFor(package)} $kTransitiveMagicString'; - } - - // Add a line for each transitive dependency and transitive dev dependency using our magic string to recognize them later. - for (final String package in transitiveDependenciesAsList) { - transitiveDependencyOutput.add(computeTransitiveDependencyLineFor(package)); - } - for (final String package in transitiveDevDependenciesAsList) { - transitiveDevDependencyOutput.add(computeTransitiveDependencyLineFor(package)); - } - - // Build a sorted list of all dependencies for the checksum. - final Set checksumDependencies = { - ...directDependencies, - ...devDependencies, - ...transitiveDependenciesAsList, - ...transitiveDevDependenciesAsList, - }..removeAll(specialDependencies); - - // Add a blank line before and after each section to keep the resulting output clean. - transitiveDependencyOutput - ..insert(0, '') - ..add(''); - transitiveDevDependencyOutput - ..insert(0, '') - ..add(''); - - // Compute a new checksum from all sorted dependencies and their version and convert to a hex string. - final String checksumString = _computeChecksum(checksumDependencies, versions.versionFor); - - // Insert the block of transitive dependency declarations into the output after [endOfDirectDependencies], - // and the blocks of transitive dev dependency declarations into the output after [lastPossiblePlace]. Finally, - // insert the [checksumString] at the very end. - output - ..insertAll(endOfDevDependencies, transitiveDevDependencyOutput) - ..insertAll(endOfDirectDependencies, transitiveDependencyOutput) - ..add('') - ..add('$kDependencyChecksum$checksumString'); - - // Remove trailing lines. - while (output.last.isEmpty) { - output.removeLast(); - } - - // Output the result to the pubspec.yaml file, skipping leading and - // duplicate blank lines and removing trailing spaces. - final StringBuffer contents = StringBuffer(); - bool hadBlankLine = true; - for (String line in output) { - line = line.trimRight(); - if (line == '') { - if (!hadBlankLine) { - contents.writeln(); - } - hadBlankLine = true; + void _checkPins(Directory directory) { + final Pubspec pubspec = Pubspec.parse(directory.childFile(_pubspecName).readAsStringSync()); + for (final MapEntry pin in kManuallyPinnedDependencies.entries) { + Dependency dependency; + if (pubspec.dependencies.containsKey(pin.key)) { + dependency = pubspec.dependencies[pin.key]!; + } else if (pubspec.devDependencies.containsKey(pin.key)) { + dependency = pubspec.devDependencies[pin.key]!; + } else if (pubspec.dependencyOverrides.containsKey(pin.key)) { + dependency = pubspec.dependencyOverrides[pin.key]!; } else { - contents.writeln(line); - hadBlankLine = false; + continue; + } + final VersionConstraint? version = switch (dependency) { + SdkDependency(:final VersionConstraint version) || + HostedDependency(:final VersionConstraint version) => version, + GitDependency() || PathDependency() => null, + }; + if (version != null && version.toString() != pin.value) { + throwToolExit( + "${pin.key} should be pinned in $directory to version ${pin.value}, but isn't", + ); } } - file.writeAsStringSync(contents.toString()); - } -} - -/// This is the base class for the objects that represent lines in the -/// pubspec.yaml files. -class PubspecLine { - PubspecLine(this.line); - - /// The raw line as we saw it in the original file. This is used so that we can - /// output the same line unmodified for the majority of lines. - final String line; -} - -/// A checksum of the non autogenerated dependencies. -class PubspecChecksum extends PubspecLine { - PubspecChecksum(this.value, String line) : super(line); - - /// The checksum value, computed using [Object.hash] over the direct, dev, - /// and special dependencies sorted lexically. - /// - /// If the line cannot be parsed, [value] will be null. - final String? value; - - /// Parses a [PubspecChecksum] from a line. - /// - /// The returned PubspecChecksum will have a null [value] if no checksum could - /// be found on this line. This is a value that [_computeChecksum] cannot return. - static PubspecChecksum parse(String line) { - final List tokens = line.split(kDependencyChecksum); - if (tokens.length != 2) { - return PubspecChecksum(null, line); - } - return PubspecChecksum(tokens.last.trim(), line); - } -} - -/// A header, e.g. "dependencies:". -class PubspecHeader extends PubspecLine { - PubspecHeader(super.line, this.section, {this.name, this.value}); - - /// The section of the pubspec where the parse [line] appears. - final Section section; - - /// The name in the pubspec line providing a name/value pair, such as "name" - /// and "version". - /// - /// Example: - /// - /// The value of this field extracted from the following line is "version". - /// - /// ```none - /// version: 0.16.5 - /// ``` - final String? name; - - /// The value in the pubspec line providing a name/value pair, such as "name" - /// and "version". - /// - /// Example: - /// - /// The value of this field extracted from the following line is "0.16.5". - /// - /// ```none - /// version: 0.16.5 - /// ``` - final String? value; - - static PubspecHeader? parse(String line) { - // We recognize any line that: - // * doesn't start with a space (i.e. is aligned on the left edge) - // * ignoring trailing spaces and comments, ends with a colon - // * has contents before the colon - // We also try to recognize which of the kinds of Sections it is - // by comparing those contents against known strings. - if (line.startsWith(' ')) { - return null; - } - final String strippedLine = _stripComments(line); - if (!strippedLine.contains(':') || strippedLine.length <= 1) { - return null; - } - final List parts = strippedLine.split(':'); - final String sectionName = parts.first; - final String value = parts.last.trim(); - return switch (sectionName) { - 'dependencies' => PubspecHeader(line, Section.dependencies), - 'dev_dependencies' => PubspecHeader(line, Section.devDependencies), - 'dependency_overrides' => PubspecHeader(line, Section.dependencyOverrides), - 'builders' => PubspecHeader(line, Section.builders), - 'name' || 'version' => PubspecHeader(line, Section.header, name: sectionName, value: value), - _ => PubspecHeader(line, Section.other), - }; - } - - /// Returns the input after removing trailing spaces and anything after the - /// first "#". - static String _stripComments(String line) { - final int hashIndex = line.indexOf('#'); - if (hashIndex < 0) { - return line.trimRight(); - } - return line.substring(0, hashIndex).trimRight(); - } -} - -/// A dependency, as represented by a line (or two) from a pubspec.yaml file. -class PubspecDependency extends PubspecLine { - PubspecDependency( - super.line, - this.name, - this.suffix, { - required this.isTransitive, - required DependencyKind kind, - required this.version, - required this.sourcePath, - required this.isDevDependency, - }) : _kind = kind; - - static PubspecDependency? parse( - String line, { - required String filename, - required bool isDevDependency, - }) { - // We recognize any line that: - // * starts with exactly two spaces, no more or less - // * has some content, then a colon - // - // If we recognize the line, then we look to see if there's anything after - // the colon, ignoring comments. If there is, then this is a normal - // dependency, otherwise it's an unknown one. - // - // We also try and save the version string, if any. This is used to verify - // the checksum of package deps. - // - // We also look at the trailing comment, if any, to see if it is the magic - // string that identifies the line as a transitive dependency that we - // previously pinned, so we can ignore it. - // - // We remember the trailing comment, if any, so that we can reconstruct the - // line later. We forget the specified version range, if any. - if (line.length < 4 || line.startsWith(' ') || !line.startsWith(' ')) { - return null; - } - final int colonIndex = line.indexOf(':'); - final int hashIndex = line.indexOf('#'); - if (colonIndex < 3) { - // two spaces at 0 and 1, a character at 2 - return null; - } - if (hashIndex >= 0 && hashIndex < colonIndex) { - return null; - } - final String package = line.substring(2, colonIndex).trimRight(); - assert(package.isNotEmpty); - assert(line.startsWith(' $package')); - String suffix = ''; - bool isTransitive = false; - String stripped; - String version = ''; - if (hashIndex >= 0) { - assert(hashIndex > colonIndex); - final String trailingComment = line.substring(hashIndex, line.length); - assert(line.endsWith(trailingComment)); - isTransitive = trailingComment == kTransitiveMagicString; - suffix = ' $trailingComment'; - stripped = line.substring(colonIndex + 1, hashIndex).trimRight(); - } else { - stripped = line.substring(colonIndex + 1, line.length).trimRight(); - } - if (colonIndex != -1) { - version = line.substring(colonIndex + 1, hashIndex != -1 ? hashIndex : line.length).trim(); - } - return PubspecDependency( - line, - package, - suffix, - isTransitive: isTransitive, - version: version, - kind: stripped.isEmpty ? DependencyKind.unknown : DependencyKind.normal, - sourcePath: filename, - isDevDependency: isDevDependency, - ); } - final String name; // the package name - final String suffix; // any trailing comment we found - final String version; // the version string if found, or blank. - final bool isTransitive; // whether the suffix matched kTransitiveMagicString - final String sourcePath; // the filename of the pubspec.yaml file, for error messages - final bool isDevDependency; // Whether this dependency is under the `dev dependencies` section. - - DependencyKind get kind => _kind; - DependencyKind _kind = DependencyKind.normal; - - /// If we're a path or sdk dependency, the path or sdk in question. - String? _lockTarget; - - /// If we were a two-line dependency, the second line (see the inherited [line] - /// for the first). - String? get lockLine => _lockLine; - String? _lockLine; - - /// If we're a path or sdk dependency, whether we were found in a - /// dependencies/dev_dependencies section, or a dependency_overrides section. - /// We track this so that we can put ourselves in the right section when - /// generating the fake pubspec.yaml. - bool _lockIsOverride = false; - - static const String _pathPrefix = ' path: '; - static const String _sdkPrefix = ' sdk: '; - static const String _gitPrefix = ' git:'; - - PubspecDependency copyWith({ - String? line, - String? name, - String? suffix, - bool? isTransitive, - DependencyKind? kind, - String? version, - String? sourcePath, - bool? isDevDependency, - }) { - return PubspecDependency( - line ?? this.line, - name ?? this.name, - suffix ?? this.suffix, - isTransitive: isTransitive ?? this.isTransitive, - kind: kind ?? this.kind, - version: version ?? this.version, - sourcePath: sourcePath ?? this.sourcePath, - isDevDependency: isDevDependency ?? this.isDevDependency, - ); - } - - /// Whether the dependency points to a package in the Flutter SDK. - /// - /// There are two ways one can point to a Flutter package: - /// - /// - Using a "sdk: flutter" dependency. - /// - Using a "path" dependency that points somewhere in the Flutter - /// repository other than the "bin" directory. - bool get pointsToSdk { - if (_kind == DependencyKind.sdk) { - return true; - } - - final String? lockTarget = _lockTarget; - if (_kind == DependencyKind.path && - lockTarget != null && - !globals.fs.path.isWithin(globals.fs.path.join(Cache.flutterRoot!, 'bin'), lockTarget) && - globals.fs.path.isWithin(Cache.flutterRoot!, lockTarget)) { - return true; + void _checkHash(String pubspec, Directory directory) { + final RegExpMatch? firstMatch = checksumRegex.firstMatch(pubspec); + if (firstMatch == null) { + throwToolExit('Pubspec in ${directory.path} does not contain a checksum.'); } - - return false; - } - - /// If parse decided we were a two-line dependency, this is called to parse the second line. - /// We throw if we couldn't parse this line. - /// We return true if we parsed it and stored the line in lockLine. - /// We return false if we parsed it and it's a git dependency that needs the next few lines. - bool parseLock(String line, String pubspecPath, {required bool lockIsOverride}) { - assert(kind == DependencyKind.unknown); - if (line.startsWith(_pathPrefix)) { - // We're a path dependency; remember the (absolute) path. - _lockTarget = globals.fs.path.canonicalize( - globals.fs.path.absolute( - globals.fs.path.dirname(pubspecPath), - line.substring(_pathPrefix.length, line.length), - ), + final String checksum = firstMatch[1]!; + final String actualChecksum = _computeChecksum(pubspec); + if (checksum != actualChecksum) { + throwToolExit( + 'Pubspec in ${directory.path} has out of date dependencies. ' + 'Please run "flutter update-packages --force-upgrade" to update them correctly. ' + 'The hash does not match the expectation.', ); - _kind = DependencyKind.path; - } else if (line.startsWith(_sdkPrefix)) { - // We're an SDK dependency. - _lockTarget = line.substring(_sdkPrefix.length, line.length); - _kind = DependencyKind.sdk; - } else if (line.startsWith(_gitPrefix)) { - // We're a git: dependency. We'll have to get the next few lines. - _kind = DependencyKind.git; - return false; - } else { - throwToolExit('Could not parse additional details for dependency $name; line was: "$line"'); } - _lockIsOverride = lockIsOverride; - _lockLine = line; - return true; - } - - void markOverridden(PubspecDependency sibling) { - // This is called when we find a dependency is mentioned a second time, - // first in dependencies/dev_dependencies, and then in dependency_overrides. - // It is called on the one found in dependencies/dev_dependencies, so that - // we'll later know to report our version as "any" in the fake pubspec.yaml - // and unmodified in the official pubspec.yamls. - assert(sibling.name == name); - assert(sibling.sourcePath == sourcePath); - assert(sibling.kind != DependencyKind.normal); - _kind = DependencyKind.overridden; } - /// This generates the entry for this dependency for the pubspec.yaml for the - /// fake package that we'll use to get the version numbers figured out. - /// - /// When called with [allowUpgrade] as `true`, the version constrains will be set - /// to >= whatever the previous version was. If [allowUpgrade] is `false`, then - /// the previous version is used again as an exact pin. - void describeForFakePubspec( - StringBuffer dependencies, - StringBuffer overrides, { - bool allowUpgrade = true, - }) { - final String versionToUse; - // This should only happen when manually adding new dependencies; otherwise - // versions should always be pinned exactly - if (version.isEmpty || version == 'any') { - versionToUse = 'any'; - } else if (allowUpgrade) { - // Must wrap in quotes for Yaml parsing - versionToUse = "'>= $version'"; - } else { - versionToUse = version; - } - switch (kind) { - case DependencyKind.unknown: - case DependencyKind.overridden: - assert(kind != DependencyKind.unknown); - case DependencyKind.normal: - if (!kManuallyPinnedDependencies.containsKey(name)) { - dependencies.writeln(' $name: $versionToUse'); - } - case DependencyKind.path: - if (_lockIsOverride) { - dependencies.writeln(' $name: $versionToUse'); - overrides.writeln(' $name:'); - overrides.writeln(' path: $_lockTarget'); - } else { - dependencies.writeln(' $name:'); - dependencies.writeln(' path: $_lockTarget'); - } - case DependencyKind.sdk: - if (_lockIsOverride) { - dependencies.writeln(' $name: $versionToUse'); - overrides.writeln(' $name:'); - overrides.writeln(' sdk: $_lockTarget'); - } else { - dependencies.writeln(' $name:'); - dependencies.writeln(' sdk: $_lockTarget'); - } - case DependencyKind.git: - if (_lockIsOverride) { - dependencies.writeln(' $name: $versionToUse'); - overrides.writeln(' $name:'); - overrides.writeln(lockLine); - } else { - dependencies.writeln(' $name:'); - dependencies.writeln(lockLine); - } - } - } - - @override - String toString() { - return '$name: $version'; - } -} - -/// Generates the File object for the pubspec.yaml file of a given Directory. -File _pubspecFor(Directory directory) { - return directory.fileSystem.file(directory.fileSystem.path.join(directory.path, 'pubspec.yaml')); -} - -/// Generates the source of a fake pubspec.yaml file given a list of -/// dependencies. -@visibleForTesting -String generateFakePubspec(Iterable dependencies, {bool doUpgrade = false}) { - final StringBuffer result = StringBuffer(); - final StringBuffer overrides = StringBuffer(); - final bool verbose = doUpgrade; - result.writeln('name: flutter_update_packages'); - result.writeln('environment:'); - result.writeln(" sdk: '>=2.12.0 <4.0.0'"); - result.writeln('dependencies:'); - overrides.writeln('dependency_overrides:'); - if (kManuallyPinnedDependencies.isNotEmpty) { - if (verbose) { - globals.printStatus('WARNING: the following packages use hard-coded version constraints:'); - } - final Set allTransitive = { - for (final PubspecDependency dependency in dependencies) dependency.name, - }; - kManuallyPinnedDependencies.forEach((String package, String version) { - // Don't add pinned dependency if it is not in the set of all transitive dependencies. - if (!allTransitive.contains(package)) { - if (verbose) { - globals.printStatus( - ' - $package: $version (skipped because it was not a transitive dependency)', - ); - } - return; - } - result.writeln(' $package: $version'); - if (verbose) { - globals.printStatus(' - $package: $version'); + void _writeHashesToPubspecs(List packages) { + globals.printStatus('Writing hashes to pubspecs...'); + for (final Directory directory in packages) { + globals.printTrace('Reading pubspec.yaml from ${directory.path}'); + final File pubspecFile = directory.childFile(_pubspecName); + String pubspec = pubspecFile.readAsStringSync(); + final String actualChecksum = _computeChecksum(pubspec); + final RegExpMatch? firstMatch = checksumRegex.firstMatch(pubspec); + if (firstMatch != null) { + pubspec = pubspec.replaceRange( + firstMatch.start, + firstMatch.end, + '$kDependencyChecksum$actualChecksum', + ); + } else { + pubspec += '\n$kDependencyChecksum$actualChecksum'; } - }); - } - if (verbose && kExplicitlyExcludedPackages.isNotEmpty) { - globals.printStatus( - 'WARNING: the following packages are explicitly excluded from version pinning', - ); - for (final String package in kExplicitlyExcludedPackages) { - globals.printStatus(' - $package'); - } - } - for (final PubspecDependency dependency in dependencies) { - if (!dependency.pointsToSdk) { - dependency.describeForFakePubspec(result, overrides, allowUpgrade: doUpgrade); - } - } - result.write(overrides.toString()); - return result.toString(); + pubspecFile.writeAsStringSync(pubspec); + } + globals.printStatus('All pubspecs are now up to date.'); + } + + String _computeChecksum(String pubspecString) { + final Pubspec pubspec = Pubspec.parse(pubspecString); + return SplayTreeMap.from({ + ...pubspec.dependencies.map( + (String key, Dependency value) => MapEntry('dep:$key', value), + ), + ...pubspec.devDependencies.map( + (String key, Dependency value) => MapEntry('dev_dep:$key', value), + ), + ...pubspec.dependencyOverrides.map( + (String key, Dependency value) => MapEntry('dep_over:$key', value), + ), + }).entries + .map((MapEntry entry) => '${entry.key}${entry.value}') + .join() + .hashCode + .toRadixString(32); + } + + /// This is the string we output next to each of our autogenerated transitive + /// dependencies so that we can ignore them the next time we parse the + /// pubspec.yaml file. + static const String kTransitiveMagicString = + '# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"'; + + /// This is the string output before a checksum of the packages used. + static const String kDependencyChecksum = '# PUBSPEC CHECKSUM: '; + final RegExp checksumRegex = RegExp('$kDependencyChecksum([a-zA-Z0-9]+)'); } -/// This object tracks the output of a call to "pub deps --style=compact". -/// -/// It ends up holding the full graph of dependencies, and the version number for -/// each one. -class PubDependencyTree { - final Map _versions = {}; - final Map> _dependencyTree = >{}; - - /// Handles the output from "pub deps --style=compact". - /// - /// That output is of this form: - /// - /// ```none - /// package_name 0.0.0 - /// - /// dependencies: - /// - analyzer 0.31.0-alpha.0 [watcher args package_config collection] - /// - archive 1.0.31 [crypto args path] - /// - args 0.13.7 - /// - cli_util 0.1.2+1 [path] - /// - /// dev dependencies: - /// - async 1.13.3 [collection] - /// - barback 0.15.2+11 [stack_trace source_span pool async collection path] - /// - /// dependency overrides: - /// - analyzer 0.31.0-alpha.0 [watcher args package_config collection] - /// ``` - /// - /// We ignore all the lines that don't start with a hyphen. For each other - /// line, we ignore any line that mentions a package we've already seen (this - /// happens when the overrides section mentions something that was in the - /// dependencies section). We ignore if something is a dependency or - /// dev_dependency (pub won't use different versions for those two). - /// - /// We then parse out the package name, version number, and sub-dependencies for - /// each entry, and store than in our _versions and _dependencyTree fields - /// above. - String? fill(String message) { - if (message.startsWith('- ')) { - final int space2 = message.indexOf(' ', 2); - int space3 = message.indexOf(' ', space2 + 1); - if (space3 < 0) { - space3 = message.length; - } - final String package = message.substring(2, space2); - if (!contains(package)) { - // Some packages get listed in the dependency overrides section too. - // We just ignore those. The data is the same either way. - final String version = message.substring(space2 + 1, space3); - List dependencies; - if (space3 < message.length) { - assert(message[space3 + 1] == '['); - assert(message[message.length - 1] == ']'); - final String allDependencies = message.substring(space3 + 2, message.length - 1); - dependencies = allDependencies.split(' '); - } else { - dependencies = const []; - } - _versions[package] = version; - _dependencyTree[package] = Set.of(dependencies); - } - } - return null; - } - - /// Whether we know about this package. - bool contains(String package) { - return _versions.containsKey(package); - } - - /// The transitive closure of all the dependencies for the given package, - /// excluding any listed in `seen`. - Iterable getTransitiveDependenciesFor( - String package, { - required Set seen, - required Set exclude, - List? result, +class ResolvedDependencies { + ResolvedDependencies([Map>? data]) + : data = data ?? >{}; + + static const String _dependencies = 'dependencies'; + static const String _devDependencies = 'dev_dependencies'; + final Map> data; + + void forEach({ + required YamlEditor yamlEditor, + required void Function( + Map dependencies, + String depType, + String packageName, + Object? version, + ) + func, }) { - result ??= []; - final Set? dependencies = _dependencyTree[package]; - if (dependencies == null) { - // We have no transitive dependencies extracted for flutter_sdk packages - // because they were omitted from pubspec.yaml used for 'pub upgrade' run. - return result; - } - for (final String dependency in dependencies) { - if (!seen.contains(dependency)) { - if (!exclude.contains(dependency)) { - result.add(dependency); - } - seen.add(dependency); - getTransitiveDependenciesFor(dependency, seen: seen, exclude: exclude, result: result); + for (final String dependencyType in [_dependencies, _devDependencies]) { + data[dependencyType] ??= {}; + final Map map = + yamlEditor.parseAt([dependencyType], orElse: () => YamlMap()) as YamlMap; + for (final MapEntry dep in map.entries) { + final String packageName = dep.key! as String; + final Object? restriction = dep.value; + func(data[dependencyType]!, dependencyType, packageName, restriction); } } - return result; } - /// The version that a particular package ended up with. - String versionFor(String package) { - return _versions[package]!; - } -} - -// Produces a 16-bit checksum from the codePoints of the package name and -// version strings using Fletcher's algorithm. -String _computeChecksum(Iterable names, String Function(String name) getVersion) { - int lowerCheck = 0; - int upperCheck = 0; - final List sortedNames = names.toList()..sort(); - for (final String name in sortedNames) { - final String version = getVersion(name); - final String value = '$name: $version'; - // Each code unit is 16 bits. - for (final int codeUnit in value.codeUnits) { - final int upper = codeUnit >> 8; - final int lower = codeUnit & 0xFF; - lowerCheck = (lowerCheck + upper) % 255; - upperCheck = (upperCheck + lowerCheck) % 255; - lowerCheck = (lowerCheck + lower) % 255; - upperCheck = (upperCheck + lowerCheck) % 255; + static ResolvedDependencies mergeDeps( + ResolvedDependencies oldDeps, + ResolvedDependencies newDeps, + List cherryPicks, + ) { + final ResolvedDependencies mergedDeps = ResolvedDependencies(>{ + ...newDeps.data, + }); + for (final MapEntry> entry in mergedDeps.data.entries) { + final String dependencyType = entry.key; + final Map? oldData = oldDeps.data[dependencyType]; + for (final MapEntry dep in entry.value.entries) { + final String packageName = dep.key; + final String newVersion = dep.value; + final String? oldVersion = + cherryPicks + .where((CherryPick pick) => pick.package == packageName) + .map((CherryPick pick) => pick.version) + .firstOrNull ?? + oldData?[packageName]; + mergedDeps.data[dependencyType]![packageName] = + oldVersion?.startsWith('^') ?? false + ? _versionWithCaret(newVersion) + : _versionWithoutCaret(newVersion); + } } + return mergedDeps; } - return ((upperCheck << 8) | lowerCheck).toRadixString(16).padLeft(4, '0'); } -/// Create a synthetic Flutter SDK so that pub version solving does not get -/// stuck on the old versions. -@visibleForTesting -Directory createTemporaryFlutterSdk( - Logger logger, - FileSystem fileSystem, - Directory realFlutter, - List pubspecs, - Directory tempDir, -) { - final Set currentPackages = {}; - for (final FileSystemEntity entity in realFlutter.childDirectory('packages').listSync()) { - // Verify that a pubspec.yaml exists to ensure this isn't a left over directory. - if (entity is Directory && entity.childFile('pubspec.yaml').existsSync()) { - currentPackages.add(fileSystem.path.basename(entity.path)); - } - } - - final Map pubspecsByName = {}; - for (final PubspecYaml pubspec in pubspecs) { - pubspecsByName[pubspec.name] = pubspec; - } - - final Directory directory = tempDir.childDirectory('flutter_upgrade_sdk')..createSync(); - // Fill in version info. - realFlutter.childFile('version').copySync(directory.childFile('version').path); - final File versionJson = FlutterVersion.getVersionFile(realFlutter.fileSystem, realFlutter.path); - final Directory binCacheDirectory = directory.childDirectory('bin').childDirectory('cache'); - binCacheDirectory.createSync(recursive: true); - versionJson.copySync(binCacheDirectory.childFile('flutter.version.json').path); +typedef CherryPick = ({String package, String version}); - // Directory structure should mirror the current Flutter SDK - final Directory packages = directory.childDirectory('packages'); - for (final String flutterPackage in currentPackages) { - final File pubspecFile = packages.childDirectory(flutterPackage).childFile('pubspec.yaml') - ..createSync(recursive: true); - final PubspecYaml? pubspecYaml = pubspecsByName[flutterPackage]; - if (pubspecYaml == null) { - logger.printWarning("Unexpected package '$flutterPackage' found in packages directory"); - continue; - } - final StringBuffer output = StringBuffer('name: $flutterPackage\n'); +/// How much dependencies should be relaxed when fetching new versions. +enum RelaxMode { + /// Relax to an `any` dep, so major changes can be made. + any, - // Fill in SDK dependency constraint. - output.write(''' -environment: - sdk: ^3.7.0-0 -'''); + /// Relax to `^...`, so only minor changes can be made. + caret, - output.writeln('dependencies:'); - for (final PubspecDependency dependency in pubspecYaml.dependencies) { - if (dependency.isTransitive || dependency.isDevDependency) { - continue; - } - if (dependency.kind == DependencyKind.sdk) { - output.writeln(' ${dependency.name}:\n sdk: flutter'); - continue; - } - output.writeln(' ${dependency.name}: any'); - } - pubspecFile.writeAsStringSync(output.toString()); - } + /// Do not relax, so keep the exact version. + strict, +} - // Create the sky engine pubspec.yaml - directory - .childDirectory('bin') - .childDirectory('cache') - .childDirectory('pkg') - .childDirectory('sky_engine') - .childFile('pubspec.yaml') - ..createSync(recursive: true) - ..writeAsStringSync(''' -name: sky_engine -version: 0.0.99 -description: Dart SDK extensions for dart:ui -homepage: http://flutter.io -# sky_engine requires sdk_ext support in the analyzer which was added in 1.11.x -environment: - sdk: ^3.7.0-0 -'''); +String _versionWithCaret(String version) => version.startsWith('^') ? version : '^$version'; - return directory; -} +String _versionWithoutCaret(String version) => + version.startsWith('^') ? version.substring(1) : version; diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index e280e0eacb595..b5683a9ea2814 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:args/args.dart'; import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; @@ -22,18 +24,17 @@ import '../convert.dart'; import '../dart/pub.dart'; import '../device.dart'; import '../flutter_manifest.dart'; -import '../linux/build_linux.dart'; -import '../macos/build_macos.dart'; +import '../globals.dart' as globals; +import '../isolated/resident_web_runner.dart'; import '../project.dart'; +import '../resident_runner.dart'; import '../runner/flutter_command.dart'; import '../runner/flutter_command_runner.dart'; import '../widget_preview/dtd_services.dart'; import '../widget_preview/preview_code_generator.dart'; import '../widget_preview/preview_detector.dart'; import '../widget_preview/preview_manifest.dart'; -import '../windows/build_windows.dart'; import 'create_base.dart'; -import 'daemon.dart'; class WidgetPreviewCommand extends FlutterCommand { WidgetPreviewCommand({ @@ -50,7 +51,7 @@ class WidgetPreviewCommand extends FlutterCommand { }) { addSubcommand( WidgetPreviewStartCommand( - verboseHelp: verboseHelp, + verbose: verboseHelp, logger: logger, fs: fs, projectFactory: projectFactory, @@ -118,7 +119,7 @@ abstract base class WidgetPreviewSubCommandBase extends FlutterCommand { final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with CreateBase { WidgetPreviewStartCommand({ - this.verboseHelp = false, + this.verbose = false, required this.logger, required this.fs, required this.projectFactory, @@ -136,18 +137,9 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C defaultsTo: true, help: 'Launches the widget preview environment.', // Should only be used for testing. - hide: !verboseHelp, - ) - ..addFlag( - kUseFlutterDesktop, - help: '(deprecated) Launches the widget preview environment using Flutter Desktop.', - hide: !verboseHelp, - ) - ..addFlag( - kHeadlessWeb, - help: 'Launches Chrome in headless mode for testing.', - hide: !verboseHelp, + hide: !verbose, ) + ..addFlag(kHeadless, help: 'Launches Chrome in headless mode for testing.', hide: !verbose) ..addOption( kWidgetPreviewScaffoldOutputDir, help: @@ -158,8 +150,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C static const String kWidgetPreviewScaffoldName = 'widget_preview_scaffold'; static const String kLaunchPreviewer = 'launch-previewer'; - static const String kUseFlutterDesktop = 'desktop'; - static const String kHeadlessWeb = 'headless-web'; + static const String kHeadless = 'headless'; static const String kWidgetPreviewScaffoldOutputDir = 'scaffold-output-dir'; /// Environment variable used to pass the DTD URI to the widget preview scaffold. @@ -177,9 +168,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C @override String get name => 'start'; - final bool verboseHelp; - - bool get isWeb => !boolArg(kUseFlutterDesktop); + final bool verbose; @override final FileSystem fs; @@ -227,7 +216,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C ); /// The currently running instance of the widget preview scaffold. - AppInstance? _widgetPreviewApp; + ResidentRunner? _widgetPreviewApp; @override Future runCommand() async { @@ -243,6 +232,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C customPreviewScaffoldOutput != null || _previewManifest.shouldGenerateProject(); // TODO(bkonyi): can this be moved? widgetPreviewScaffold.createSync(); + fs.currentDirectory = widgetPreviewScaffold; if (generateScaffoldProject) { // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart @@ -258,27 +248,22 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C titleCaseProjectName: 'Widget Preview Scaffold', flutterRoot: Cache.flutterRoot!, dartSdkVersionBounds: '^${cache.dartSdkBuild}', - linux: platform.isLinux && !isWeb, - macos: platform.isMacOS && !isWeb, - windows: platform.isWindows && !isWeb, - web: isWeb, + web: true, ), overwrite: true, generateMetadata: false, + printStatusWhenWriting: verbose, ); if (customPreviewScaffoldOutput != null) { return FlutterCommandResult.success(); } _previewManifest.generate(); - - // WARNING: this access of widgetPreviewScaffoldProject needs to happen - // after we generate the scaffold project as invoking the getter triggers - // lazy initialization of the preview scaffold's FlutterManifest before - // the scaffold project's pubspec has been generated. - // TODO(bkonyi): add logic to rebuild after SDK updates - await initialBuild(widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject); } + // WARNING: this access of widgetPreviewScaffoldProject needs to happen + // after we generate the scaffold project as invoking the getter triggers + // lazy initialization of the preview scaffold's FlutterManifest before + // the scaffold project's pubspec has been generated. _previewCodeGenerator = PreviewCodeGenerator( widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject, fs: fs, @@ -305,13 +290,13 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C if (boolArg(kLaunchPreviewer)) { shutdownHooks.addShutdownHook(() async { - await _widgetPreviewApp?.stop(); + await _widgetPreviewApp?.exitApp(); }); await configureDtd(); _widgetPreviewApp = await runPreviewEnvironment( widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject, ); - final int result = await _widgetPreviewApp!.runner.waitForAppToFinish(); + final int result = await _widgetPreviewApp!.waitForAppToFinish(); if (result != 0) { throwToolExit('Failed to launch the widget previewer.', exitCode: result); } @@ -358,119 +343,13 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C } } - /// Builds the application binary for the widget preview scaffold the first - /// time the widget preview command is run. - /// - /// The resulting binary is used to speed up subsequent widget previewer launches - /// by acting as a basic scaffold to load previews into using hot reload / restart. - Future initialBuild({required FlutterProject widgetPreviewScaffoldProject}) async { - // Generate initial package_config.json, otherwise the build will fail. - await pub.get( - context: PubContext.create, - project: widgetPreviewScaffoldProject, - offline: offline, - outputMode: PubOutputMode.summaryOnly, - ); - - // TODO(bkonyi): handle error case where desktop device isn't enabled. - await widgetPreviewScaffoldProject.ensureReadyForPlatformSpecificTooling( - releaseMode: false, - linuxPlatform: platform.isLinux && !isWeb, - macOSPlatform: platform.isMacOS && !isWeb, - windowsPlatform: platform.isWindows && !isWeb, - webPlatform: isWeb, - ); - - if (isWeb) { - return; - } - - // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart - logger.printStatus('Performing initial build of the Widget Preview Scaffold...'); - - final BuildInfo buildInfo = BuildInfo( - BuildMode.debug, - null, - treeShakeIcons: false, - packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path, - ); - - if (platform.isMacOS) { - await buildMacOS( - flutterProject: widgetPreviewScaffoldProject, - buildInfo: buildInfo, - verboseLogging: false, - ); - } else if (platform.isLinux) { - await buildLinux( - widgetPreviewScaffoldProject.linux, - buildInfo, - targetPlatform: - os.hostPlatform == HostPlatform.linux_x64 - ? TargetPlatform.linux_x64 - : TargetPlatform.linux_arm64, - logger: logger, - ); - } else if (platform.isWindows) { - await buildWindows( - widgetPreviewScaffoldProject.windows, - buildInfo, - os.hostPlatform == HostPlatform.windows_x64 - ? TargetPlatform.windows_x64 - : TargetPlatform.windows_arm64, - ); - } else { - throw UnimplementedError(); - } - // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart - logger.printStatus('Widget Preview Scaffold initial build complete.'); - } - - /// Returns the path to a prebuilt widget_preview_scaffold application binary. - String prebuiltApplicationBinaryPath({required FlutterProject widgetPreviewScaffoldProject}) { - assert(platform.isLinux || platform.isMacOS || platform.isWindows); - String path; - if (platform.isMacOS) { - path = fs.path.join( - getMacOSBuildDirectory(), - 'Build/Products/Debug/widget_preview_scaffold.app', - ); - } else if (platform.isLinux) { - path = fs.path.join( - getLinuxBuildDirectory( - os.hostPlatform == HostPlatform.linux_x64 - ? TargetPlatform.linux_x64 - : TargetPlatform.linux_arm64, - ), - 'debug/bundle/widget_preview_scaffold', - ); - } else if (platform.isWindows) { - path = fs.path.join( - getWindowsBuildDirectory( - os.hostPlatform == HostPlatform.windows_x64 - ? TargetPlatform.windows_x64 - : TargetPlatform.windows_arm64, - ), - 'runner/Debug/widget_preview_scaffold.exe', - ); - } else { - throw StateError('Unknown OS'); - } - path = fs.path.join(widgetPreviewScaffoldProject.directory.path, path); - if (fs.typeSync(path) == FileSystemEntityType.notFound) { - logger.printStatus(fs.currentDirectory.toString()); - throw StateError('Could not find prebuilt application binary at $path.'); - } - return path; - } - - Future runPreviewEnvironment({ + Future runPreviewEnvironment({ required FlutterProject widgetPreviewScaffoldProject, }) async { - final AppInstance app; + final ResidentWebRunner runner; try { - // Since the only target supported by the widget preview scaffold is the host's desktop - // device, only a single desktop device should be returned. + // Since the only target supported by the widget preview scaffold is the web + // device, only a single web device should be returned. final List devices = await deviceManager!.getDevices( filter: DeviceDiscoveryFilter( supportFilter: DeviceDiscoverySupportFilter.excludeDevicesUnsupportedByFlutterOrProject( @@ -482,71 +361,62 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C assert(devices.length == 1); final Device device = devices.first; - // We launch from a prebuilt widget preview scaffold instance to reduce launch times after - // the first run. - File? prebuiltApplicationBinary; - if (!isWeb) { - prebuiltApplicationBinary = fs.file( - prebuiltApplicationBinaryPath(widgetPreviewScaffoldProject: widgetPreviewScaffoldProject), - ); - } - const String? kEmptyRoute = null; - const bool kEnableHotReload = true; - // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart logger.printStatus('Launching the Widget Preview Scaffold...'); - app = await Daemon.createMachineDaemon().appDomain.startApp( - device, - widgetPreviewScaffoldProject.directory.path, - bundle.defaultMainPath, - kEmptyRoute, // route - DebuggingOptions.enabled( - BuildInfo( - BuildMode.debug, - null, - treeShakeIcons: false, - // Provide the DTD connection information directly to the preview scaffold. - // This could, in theory, be provided via a follow up call to a service extension - // registered by the preview scaffold, but there's some uncertainty around how service - // extensions will work with Flutter web embedded in VSCode without a Chrome debugger - // connection. - dartDefines: ['$kWidgetPreviewDtdUriEnvVar=${_dtdService.dtdUri}'], - extraFrontEndOptions: - isWeb ? ['--dartdevc-canary', '--dartdevc-module-format=ddc'] : null, - packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path, - packageConfig: PackageConfig.parseBytes( - widgetPreviewScaffoldProject.packageConfig.readAsBytesSync(), - widgetPreviewScaffoldProject.packageConfig.uri, - ), - // Don't try and download canvaskit from the CDN. - useLocalCanvasKit: true, + final DebuggingOptions debuggingOptions = DebuggingOptions.enabled( + BuildInfo( + BuildMode.debug, + null, + treeShakeIcons: false, + // Provide the DTD connection information directly to the preview scaffold. + // This could, in theory, be provided via a follow up call to a service extension + // registered by the preview scaffold, but there's some uncertainty around how service + // extensions will work with Flutter web embedded in VSCode without a Chrome debugger + // connection. + dartDefines: ['$kWidgetPreviewDtdUriEnvVar=${_dtdService.dtdUri}'], + packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path, + packageConfig: PackageConfig.parseBytes( + widgetPreviewScaffoldProject.packageConfig.readAsBytesSync(), + widgetPreviewScaffoldProject.packageConfig.uri, ), - webEnableExposeUrl: false, - webRunHeadless: boolArg(kHeadlessWeb), + // Don't try and download canvaskit from the CDN. + useLocalCanvasKit: true, ), - kEnableHotReload, // hot mode - applicationBinary: prebuiltApplicationBinary, - trackWidgetCreation: true, - projectRootPath: widgetPreviewScaffoldProject.directory.path, + webEnableExposeUrl: false, + webRunHeadless: boolArg(kHeadless), + ); + final String target = bundle.defaultMainPath; + final FlutterDevice flutterDevice = await FlutterDevice.create( + device, + target: target, + buildInfo: debuggingOptions.buildInfo, + platform: platform, ); - app.runner.residentDevtoolsHandler!.launchDevToolsInBrowser( - flutterDevices: app.runner.flutterDevices, + + runner = ResidentWebRunner( + flutterDevice, + target: target, + debuggingOptions: debuggingOptions, + analytics: analytics, + flutterProject: widgetPreviewScaffoldProject, + fileSystem: fs, + logger: logger, + terminal: globals.terminal, + platform: platform, + outputPreferences: globals.outputPreferences, + systemClock: globals.systemClock, ); + final Completer appStarted = Completer(); + unawaited(runner.run(appStartedCompleter: appStarted)); + await appStarted.future; } on Exception catch (error) { throwToolExit(error.toString()); } - if (!isWeb) { - // Immediately perform a hot restart to ensure new previews are loaded into the prebuilt - // application. - // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart - logger.printStatus('Loading previews into the Widget Preview Scaffold...'); - await app.restart(fullRestart: true); - } // WARNING: this log message is used by test/integration.shard/widget_preview_test.dart logger.printStatus('Done loading previews.'); - return app; + return runner; } @visibleForTesting @@ -643,6 +513,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C 'path': rootProject.directory.fileSystem.path.relative(rootProject.directory.path), }); + final PubOutputMode outputMode = verbose ? PubOutputMode.all : PubOutputMode.failuresOnly; await pub.interactively( [ pubAdd, @@ -655,6 +526,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C context: PubContext.pubAdd, command: pubAdd, touchesPackageConfig: true, + outputMode: outputMode, ); // Adds dependencies on: @@ -679,6 +551,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C context: PubContext.pubAdd, command: pubAdd, touchesPackageConfig: true, + outputMode: outputMode, ); // Generate package_config.json. @@ -686,7 +559,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C context: PubContext.create, project: widgetPreviewScaffoldProject, offline: offline, - outputMode: PubOutputMode.summaryOnly, + outputMode: outputMode, ); maybeAddFlutterGenToPackageConfig(rootProject: rootProject); diff --git a/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart b/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart deleted file mode 100644 index d80dba8c640de..0000000000000 --- a/packages/flutter_tools/lib/src/dart/generate_synthetic_packages.dart +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:yaml/yaml.dart'; - -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../base/utils.dart'; -import '../build_system/build_system.dart'; -import '../build_system/build_targets.dart'; -import '../features.dart'; - -/// Generates the `package:flutter_gen` synthetic package. -/// -/// If the package has been configured *not* to use synthetic packages, this -/// method is a NO-OP and returns `false`. -/// -/// Returns `true` if the package was generated, or `false` it was not. -Future generateLocalizationsSyntheticPackage({ - required Environment environment, - required BuildSystem buildSystem, - required BuildTargets buildTargets, -}) async { - final FileSystem fileSystem = environment.fileSystem; - final File l10nYamlFile = fileSystem.file( - fileSystem.path.join(environment.projectDir.path, 'l10n.yaml'), - ); - - // If pubspec.yaml has generate:true and if l10n.yaml exists in the - // root project directory, check to see if a synthetic package should - // be generated for gen_l10n. - if (!l10nYamlFile.existsSync()) { - return false; - } - - final YamlNode yamlNode = loadYamlNode(l10nYamlFile.readAsStringSync()); - if (yamlNode.value != null && yamlNode is! YamlMap) { - throwToolExit('Expected ${l10nYamlFile.path} to contain a map, instead was $yamlNode'); - } - - // If an l10n.yaml file exists and is not empty, attempt to parse settings in - // it. - if (yamlNode.value != null) { - final YamlMap yamlMap = yamlNode as YamlMap; - final Object? value = yamlMap['synthetic-package']; - if (value is! bool && value != null) { - throwToolExit('Expected "synthetic-package" to have a bool value, instead was "$value"'); - } - - // Generate gen_l10n synthetic package only if synthetic-package: true or - // synthetic-package is null. - final bool? isSyntheticL10nPackage = value as bool?; - if (isSyntheticL10nPackage == false || - isSyntheticL10nPackage == null && featureFlags.isExplicitPackageDependenciesEnabled) { - return false; - } - } else if (featureFlags.isExplicitPackageDependenciesEnabled) { - // synthetic-packages: true was not set and it is no longer the default. - return false; - } - - if (featureFlags.isExplicitPackageDependenciesEnabled) { - throwToolExit( - 'Cannot generate a synthetic package when explicit-package-dependencies is enabled.\n' - '\n' - 'Synthetic package output (package:flutter_gen) is deprecated: ' - 'https://flutter.dev/to/flutter-gen-deprecation. If you are seeing this ' - 'message either you have provided explicit-package-dependencies, or it ' - 'is the default value (see flutter config --help).', - ); - } - - // Log a warning: synthetic-package: true (or implicit true) is deprecated. - environment.logger.printWarning( - 'Synthetic package output (package:flutter_gen) is deprecated: ' - 'https://flutter.dev/to/flutter-gen-deprecation. In a future release, ' - 'synthetic-package will default to `false` and will later be removed ' - 'entirely.', - ); - - final BuildResult result = await buildSystem.build( - buildTargets.generateLocalizationsTarget, - environment, - ); - - if (result.hasException) { - throwToolExit( - 'Generating synthetic localizations package failed with ${result.exceptions.length} ${pluralize('error', result.exceptions.length)}:' - '\n\n' - '${result.exceptions.values.map((ExceptionMeasurement e) => e.exception).join('\n\n')}', - ); - } - - return true; -} diff --git a/packages/flutter_tools/lib/src/dart/pub.dart b/packages/flutter_tools/lib/src/dart/pub.dart index 57c723c3c6215..ec64c9b69cac9 100644 --- a/packages/flutter_tools/lib/src/dart/pub.dart +++ b/packages/flutter_tools/lib/src/dart/pub.dart @@ -8,7 +8,6 @@ library; import 'dart:async'; import 'package:meta/meta.dart'; -import 'package:package_config/package_config.dart'; import 'package:process/process.dart'; import '../base/bot_detector.dart'; import '../base/common.dart'; @@ -152,6 +151,7 @@ abstract class Pub { String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }); @@ -243,6 +243,7 @@ class _DefaultPub implements Pub { String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async { final String directory = project.directory.path; @@ -332,6 +333,7 @@ class _DefaultPub implements Pub { ...[command], if (offline) '--offline', '--example', + if (enforceLockfile) '--enforce-lockfile', ]; await _runWithStdioInherited( args, @@ -660,9 +662,6 @@ class _DefaultPub implements Pub { /// Updates the .dart_tool/version file to be equal to current Flutter /// version. /// - /// Calls [_updatePackageConfig] for [project] and [FlutterProject.example] - /// (if it exists). - /// /// This should be called after pub invocations that are expected to update /// the packageConfig. Future _updateVersionAndPackageConfig(FlutterProject project) async { @@ -680,7 +679,6 @@ class _DefaultPub implements Pub { ); lastVersion.writeAsStringSync(currentVersion.readAsStringSync()); - await _updatePackageConfig(project, packageConfig); if (project.hasExampleApp && project.example.pubspecFile.existsSync()) { final File? examplePackageConfig = findPackageConfigFile(project.example.directory); if (examplePackageConfig == null) { @@ -688,36 +686,6 @@ class _DefaultPub implements Pub { '${project.directory}: pub did not create example/.dart_tools/package_config.json file.', ); } - await _updatePackageConfig(project.example, examplePackageConfig); } } - - /// Update the package configuration file in [project]. - /// - /// Creates a corresponding `package_config_subset` file that is used by the - /// build system to avoid rebuilds caused by an updated pub timestamp. - Future _updatePackageConfig(FlutterProject project, File packageConfigFile) async { - final PackageConfig packageConfig = await loadPackageConfigWithLogging( - packageConfigFile, - logger: _logger, - ); - - packageConfigFile.parent - .childFile('package_config_subset') - .writeAsStringSync(_computePackageConfigSubset(packageConfig, _fileSystem)); - } - - // Subset the package config file to only the parts that are relevant for - // rerunning the dart compiler. - String _computePackageConfigSubset(PackageConfig packageConfig, FileSystem fileSystem) { - final StringBuffer buffer = StringBuffer(); - for (final Package package in packageConfig.packages) { - buffer.writeln(package.name); - buffer.writeln(package.languageVersion); - buffer.writeln(package.root); - buffer.writeln(package.packageUriRoot); - } - buffer.writeln(packageConfig.version); - return buffer.toString(); - } } diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index d548d2b49e42f..f28cb490e69ca 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -53,35 +53,32 @@ abstract class FeatureFlags { /// Whether Swift Package Manager dependency management is enabled. bool get isSwiftPackageManagerEnabled => false; - /// Whether explicit package dependency management is enabled. - bool get isExplicitPackageDependenciesEnabled => false; - /// Whether a particular feature is enabled for the current channel. /// /// Prefer using one of the specific getters above instead of this API. bool isEnabled(Feature feature); -} -/// All current Flutter feature flags. -const List allFeatures = [ - flutterWebFeature, - flutterLinuxDesktopFeature, - flutterMacOSDesktopFeature, - flutterWindowsDesktopFeature, - flutterAndroidFeature, - flutterIOSFeature, - flutterFuchsiaFeature, - flutterCustomDevicesFeature, - cliAnimation, - nativeAssets, - swiftPackageManager, -]; + /// All current Flutter feature flags. + List get allFeatures => const [ + flutterWebFeature, + flutterLinuxDesktopFeature, + flutterMacOSDesktopFeature, + flutterWindowsDesktopFeature, + flutterAndroidFeature, + flutterIOSFeature, + flutterFuchsiaFeature, + flutterCustomDevicesFeature, + cliAnimation, + nativeAssets, + swiftPackageManager, + ]; +} /// All current Flutter feature flags that can be configured. /// /// [Feature.configSetting] is not `null`. Iterable get allConfigurableFeatures => - allFeatures.where((Feature feature) => feature.configSetting != null); + featureFlags.allFeatures.where((Feature feature) => feature.configSetting != null); /// The [Feature] for flutter web. const Feature flutterWebFeature = Feature.fullyEnabled( diff --git a/packages/flutter_tools/lib/src/flutter_application_package.dart b/packages/flutter_tools/lib/src/flutter_application_package.dart index a8aff4f20cc94..5c8adf4db438c 100644 --- a/packages/flutter_tools/lib/src/flutter_application_package.dart +++ b/packages/flutter_tools/lib/src/flutter_application_package.dart @@ -54,7 +54,6 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: if (applicationBinary == null) { return AndroidApk.fromAndroidProject( FlutterProject.current().android, diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index f9dcca8773878..8955ac5967c64 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -740,9 +740,10 @@ class IosUsbArtifacts extends CachedArtifact { static const List artifactNames = [ 'libimobiledevice', - 'usbmuxd', + 'libusbmuxd', 'libplist', 'openssl', + 'libimobiledeviceglue', 'ios-deploy', ]; @@ -752,7 +753,7 @@ class IosUsbArtifacts extends CachedArtifact { // missing. static const Map> _kExecutables = >{ 'libimobiledevice': ['idevicescreenshot', 'idevicesyslog'], - 'usbmuxd': ['iproxy'], + 'libusbmuxd': ['iproxy'], }; @override diff --git a/packages/flutter_tools/lib/src/flutter_features.dart b/packages/flutter_tools/lib/src/flutter_features.dart index a55f54c7afd37..0f3bf3020836f 100644 --- a/packages/flutter_tools/lib/src/flutter_features.dart +++ b/packages/flutter_tools/lib/src/flutter_features.dart @@ -51,17 +51,9 @@ mixin FlutterFeatureFlagsIsEnabled implements FeatureFlags { @override bool get isSwiftPackageManagerEnabled => isEnabled(swiftPackageManager); - - // TODO(matanlurey): Remove this when the flag is no longer in use. - // - // Setting this always to true prevents `false` from ever being returned in - // production code, but still allows tests to override it so that they can be - // migrated (or deleted) one at a time instead of a single large PR. - @override - bool get isExplicitPackageDependenciesEnabled => true; } -interface class FlutterFeatureFlags with FlutterFeatureFlagsIsEnabled implements FeatureFlags { +interface class FlutterFeatureFlags extends FeatureFlags with FlutterFeatureFlagsIsEnabled { FlutterFeatureFlags({ required FlutterVersion flutterVersion, required FlutterFeaturesConfig featuresConfig, diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index fdc1b3075f3d2..eb2d81bdd0006 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -421,16 +421,6 @@ class FlutterManifest { } /// Whether localization Dart files should be generated. - /// - /// **NOTE**: This method was previously called `generateSyntheticPackage`, - /// which was incorrect; the presence of `generate: true` in `pubspec.yaml` - /// does _not_ imply a synthetic package (and never did); additional - /// introspection is required to determine whether a synthetic package is - /// required. - /// - /// See also: - /// - /// * [Deprecate and remove synthethic `package:flutter_gen`](https://github.com/flutter/flutter/issues/102983) late final bool generateLocalizations = _flutterDescriptor['generate'] == true; String? get defaultFlavor => _flutterDescriptor['default-flavor'] as String?; @@ -965,10 +955,10 @@ final class AssetTransformerEntry { : args = args ?? const []; final String package; - final List? args; + final List args; Map get descriptor { - return {_kPackage: package, if (args != null) _kArgs: args}; + return {_kPackage: package, _kArgs: args}; } static const String _kPackage = 'package'; @@ -1018,30 +1008,22 @@ final class AssetTransformerEntry { if (other is! AssetTransformerEntry) { return false; } - - final bool argsAreEqual = - (() { - if (args == null && other.args == null) { - return true; - } - if (args?.length != other.args?.length) { - return false; - } - - for (int index = 0; index < args!.length; index += 1) { - if (args![index] != other.args![index]) { - return false; - } - } - return true; - })(); - - return package == other.package && argsAreEqual; + if (package != other.package) { + return false; + } + if (args.length != other.args.length) { + return false; + } + for (int index = 0; index < args.length; index += 1) { + if (args[index] != other.args[index]) { + return false; + } + } + return true; } @override - int get hashCode => - Object.hashAll([package.hashCode, args?.map((String e) => e.hashCode)]); + int get hashCode => Object.hash(package, Object.hashAll(args)); @override String toString() { diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 43ff596afa3c3..aaf0f390a233e 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -130,8 +130,7 @@ Future> findPlugins(FlutterProject project, {bool throwOnError = tr packageName, dependency.rootUri, project.manifest.dependencies, - isDevDependency: - featureFlags.isExplicitPackageDependenciesEnabled && dependency.isExclusiveDevDependency, + isDevDependency: dependency.isExclusiveDevDependency, fileSystem: fs, ); if (plugin != null) { @@ -1160,8 +1159,7 @@ void _createPlatformPluginSymlinks( /// /// Assumes `pub get` has been executed since last change to `pubspec.yaml`. /// -/// If [FeatureFlags.isExplicitPackageDependenciesEnabled] is `true`, -/// plugins that are development-only dependencies might be labeled or, +/// Plugins that are development-only dependencies might be labeled or, /// depending on the platform, omitted from metadata or platform-specific artifacts. Future refreshPluginsList( FlutterProject project, { diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index b7aed7cf48cac..a349c615cea79 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -23,7 +23,6 @@ import '../convert.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; import '../device_vm_service_discovery_for_attach.dart'; -import '../features.dart'; import '../globals.dart' as globals; import '../macos/xcdevice.dart'; import '../mdns_discovery.dart'; @@ -701,7 +700,6 @@ class IOSDevice extends Device { await updateGeneratedXcodeProperties( project: FlutterProject.current(), buildInfo: debuggingOptions.buildInfo, - featureFlags: featureFlags, targetOverride: mainPath, ); } @@ -945,7 +943,6 @@ class IOSDevice extends Device { await updateGeneratedXcodeProperties( project: flutterProject, buildInfo: debuggingOptions.buildInfo, - featureFlags: featureFlags, targetOverride: mainPath, configurationBuildDir: bundle.parent.absolute.path, ); diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 97904dd30f7a6..484eecd3e5751 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -18,7 +18,6 @@ import '../base/utils.dart'; import '../build_info.dart'; import '../cache.dart'; import '../device.dart'; -import '../features.dart'; import '../flutter_manifest.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; @@ -43,6 +42,7 @@ import 'migrations/project_build_location_migration.dart'; import 'migrations/remove_bitcode_migration.dart'; import 'migrations/remove_framework_link_and_embedding_migration.dart'; import 'migrations/uiapplicationmain_deprecation_migration.dart'; +import 'migrations/uiscenedelegate_migration.dart'; import 'migrations/xcode_build_system_migration.dart'; import 'xcode_build_settings.dart'; import 'xcodeproj.dart'; @@ -153,6 +153,7 @@ Future buildXcodeProject({ IOSDeploymentTargetMigration(app.project, globals.logger), XcodeProjectObjectVersionMigration(app.project, globals.logger), HostAppInfoPlistMigration(app.project, globals.logger), + UISceneDelegateMigration(app.project, globals.logger), XcodeScriptBuildPhaseMigration(app.project, globals.logger), RemoveBitcodeMigration(app.project, globals.logger), XcodeThinBinaryBuildPhaseInputPathsMigration(app.project, globals.logger), @@ -290,7 +291,6 @@ Future buildXcodeProject({ project: project, targetOverride: targetOverride, buildInfo: buildInfo, - featureFlags: featureFlags, ); if (app.project.usesSwiftPackageManager) { final String? iosDeploymentTarget = buildSettings['IPHONEOS_DEPLOYMENT_TARGET']; @@ -418,6 +418,8 @@ Future buildXcodeProject({ Future listenToScriptOutputLine() async { final List lines = await scriptOutputPipeFile!.readAsLines(); + bool inWarningBlock = false; + bool inNoteBlock = false; for (final String line in lines) { if (line == 'done' || line == 'all done') { buildSubStatus?.stop(); @@ -426,6 +428,25 @@ Future buildXcodeProject({ return; } } else { + if (!globals.logger.isVerbose) { + if (line.contains('error:')) { + globals.printError(line); + } else if (line.contains('warning:')) { + globals.printWarning(line); + inWarningBlock = true; + } else if (inNoteBlock) { + globals.printWarning(line); + inNoteBlock = false; + } else if (inWarningBlock) { + if (line.startsWith(RegExp(r'\s+?note[:]'))) { + // Xcode doesn't echo this, so we don't. + inNoteBlock = true; + } + inWarningBlock = false; + } + continue; + } + initialBuildStatus?.cancel(); initialBuildStatus = null; buildSubStatus = globals.logger.startProgress( diff --git a/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart b/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart new file mode 100644 index 0000000000000..0aa9a86934782 --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart @@ -0,0 +1,94 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart' show visibleForTesting; +import 'package:xml/xml.dart'; + +import '../../base/file_system.dart'; +import '../../base/project_migrator.dart'; +import '../../xcode_project.dart'; + +const String _manifestKey = 'UIApplicationSceneManifest'; +const String _storyboardKey = 'UIMainStoryboardFile'; + +String _addition(String storyboard) => ''' +UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + $storyboard + + + + +'''; + +/// Update Info.plist. +class UISceneDelegateMigration extends ProjectMigrator { + UISceneDelegateMigration(IosProject project, super.logger) + : _infoPlist = project.defaultHostInfoPlist; + + final File _infoPlist; + + @override + Future migrate() async { + if (!_infoPlist.existsSync()) { + logger.printTrace('Info.plist not found, skipping host app Info.plist migration.'); + return; + } + + processFileLines(_infoPlist); + } + + @visibleForTesting + static Map extractPlistDict(XmlElement dict) { + final Map keyValues = {}; + String? key; + for (final XmlElement child in dict.childElements) { + if (key != null) { + keyValues[key] = child; + key = null; + } else { + key = child.innerText; + } + } + return keyValues; + } + + @override + String migrateFileContents(String fileContents) { + try { + final XmlDocument read = XmlDocument.parse(fileContents); + final XmlElement readPlist = read.childElements.first; + final XmlElement readDict = readPlist.childElements.first; + final Map keyValues = extractPlistDict(readDict); + + if (!keyValues.containsKey(_manifestKey)) { + if (keyValues.containsKey(_storyboardKey)) { + final String storyboard = keyValues[_storyboardKey]!.innerText; + final String xmlAddition = _addition(storyboard); + final XmlDocumentFragment fragment = XmlDocumentFragment.parse(xmlAddition); + for (final XmlNode node in fragment.children) { + readDict.children.add(node.copy()); + } + } + } + return '${read.toXmlString(pretty: true)}\n'; + } on Exception catch (_) { + return fileContents; + } + } +} 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 d197625676b13..13d24cc9202b8 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -7,7 +7,6 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_manifest.dart'; import '../globals.dart' as globals; import '../project.dart'; @@ -31,21 +30,14 @@ String flutterMacOSFrameworkDir(BuildMode mode, FileSystem fileSystem, Artifacts Future updateGeneratedXcodeProperties({ required FlutterProject project, required BuildInfo buildInfo, - required FeatureFlags featureFlags, String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, String? configurationBuildDir, }) async { - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; - final List xcodeBuildSettings = await _xcodeBuildSettingsLines( project: project, buildInfo: buildInfo, - devDependenciesEnabled: devDependenciesEnabled, targetOverride: targetOverride, useMacOSConfig: useMacOSConfig, buildDirOverride: buildDirOverride, @@ -154,7 +146,6 @@ String? parsedBuildNumber({required FlutterManifest manifest, BuildInfo? buildIn Future> _xcodeBuildSettingsLines({ required FlutterProject project, required BuildInfo buildInfo, - required bool devDependenciesEnabled, String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, @@ -190,11 +181,8 @@ Future> _xcodeBuildSettingsLines({ parsedBuildNumber(manifest: project.manifest, buildInfo: buildInfo) ?? '1'; xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber'); - // Whether the current project can have dev dependencies. - // If true, the project should be built using debug mode. - // If false, the project should be build using release or profile mode. - // This can be true even if the project has no dev dependencies. - xcodeBuildSettings.add('FLUTTER_DEV_DEPENDENCIES_ENABLED=$devDependenciesEnabled'); + // The current build mode being targeted. + xcodeBuildSettings.add('FLUTTER_CLI_BUILD_MODE=${buildInfo.mode.cliName}'); // CoreDevices in debug and profile mode are launched, but not built, via Xcode. // Set the CONFIGURATION_BUILD_DIR so Xcode knows where to find the app diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index 877a234199b9d..e7fdea27bbd2b 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -918,7 +918,9 @@ class WebDevFS implements DevFS { /// Connect and retrieve the [DebugConnection] for the current application. /// - /// Only calls [AppConnection.runMain] on the subsequent connections. + /// Only calls [AppConnection.runMain] on the subsequent connections. This + /// should be called before the browser is launched to make sure the listener + /// is registered early enough. Future connect( bool useDebugExtension, { @visibleForTesting VmServiceFactory vmServiceFactory = createVmServiceDelegate, diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart index 9f507317a4670..7562d31a27493 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart @@ -46,7 +46,6 @@ Architecture getNativeAndroidArchitecture(AndroidArch androidArch) { return switch (androidArch) { AndroidArch.armeabi_v7a => Architecture.arm, AndroidArch.arm64_v8a => Architecture.arm64, - AndroidArch.x86 => Architecture.ia32, AndroidArch.x86_64 => Architecture.x64, }; } @@ -56,7 +55,6 @@ AndroidArch _getAndroidArch(Architecture architecture) { return switch (architecture) { Architecture.arm => AndroidArch.armeabi_v7a, Architecture.arm64 => AndroidArch.arm64_v8a, - Architecture.ia32 => AndroidArch.x86, Architecture.x64 => AndroidArch.x86_64, Architecture.riscv64 => throwToolExit('Android RISC-V not yet supported.'), _ => throwToolExit('Invalid architecture: $architecture.'), diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart index 83f368294980e..04c2ed0b02e4f 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart @@ -728,7 +728,6 @@ Architecture _getNativeArchitecture(TargetPlatform targetPlatform) { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: throw Exception('Unknown targetPlatform: $targetPlatform.'); } } @@ -781,7 +780,6 @@ OS getNativeOSFromTargetPlatform(TargetPlatform platform) { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: return OS.android; case TargetPlatform.tester: if (const LocalPlatform().isMacOS) { @@ -806,8 +804,6 @@ List _androidArchs(TargetPlatform targetPlatform, String? androidAr return [AndroidArch.arm64_v8a]; case TargetPlatform.android_x64: return [AndroidArch.x86_64]; - case TargetPlatform.android_x86: - return [AndroidArch.x86]; case TargetPlatform.android: if (androidArchsEnvironment == null) { throw MissingDefineException(kAndroidArchs, 'native_assets'); 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 5c02901f57202..d11c3cfb26e73 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -167,12 +167,13 @@ class ResidentWebRunner extends ResidentRunner { @override bool get reloadIsRestart => + debuggingOptions.webUseWasm || // Web behavior when not using the DDC library bundle format is to restart // when a reload is issued. We can't use `canHotReload` to signal this // since we still want a reload command to succeed, but to do a hot // restart. debuggingOptions.buildInfo.ddcModuleFormat != DdcModuleFormat.ddc || - debuggingOptions.buildInfo.canaryFeatures != true; + !debuggingOptions.buildInfo.canaryFeatures; @override bool get supportsDetach => stopAppDuringCleanup; @@ -321,7 +322,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). chromiumLauncher: _chromiumLauncher, nativeNullAssertions: debuggingOptions.nativeNullAssertions, ddcModuleSystem: debuggingOptions.buildInfo.ddcModuleFormat == DdcModuleFormat.ddc, - canaryFeatures: debuggingOptions.buildInfo.canaryFeatures ?? false, + canaryFeatures: debuggingOptions.buildInfo.canaryFeatures, webRenderer: debuggingOptions.webRenderer, isWasm: debuggingOptions.webUseWasm, useLocalCanvasKit: debuggingOptions.buildInfo.useLocalCanvasKit, @@ -359,6 +360,13 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). compilerConfigs: [_compilerConfig], ); } + final WebDevFS webDevFS = device!.devFS! as WebDevFS; + final bool useDebugExtension = + device!.device is WebServerDevice && debuggingOptions.startPaused; + // Listen for connected apps early and then await this `Future` later + // when we attach. + final Future? connectDebug = + supportsServiceProtocol ? webDevFS.connect(useDebugExtension) : null; await device!.device!.startApp( package, mainPath: target, @@ -368,6 +376,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). return attach( connectionInfoCompleter: connectionInfoCompleter, appStartedCompleter: appStartedCompleter, + connectDebug: connectDebug, ); }); } on WebSocketException catch (error, stackTrace) { @@ -420,7 +429,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). final DateTime start = _systemClock.now(); final Status status; if (debuggingOptions.buildInfo.ddcModuleFormat != DdcModuleFormat.ddc || - debuggingOptions.buildInfo.canaryFeatures == false) { + !debuggingOptions.buildInfo.canaryFeatures) { // Triggering hot reload performed hot restart for the old module formats // historically. Keep that behavior and only perform hot reload when the // new module format is used. @@ -754,6 +763,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). Future attach({ Completer? connectionInfoCompleter, Completer? appStartedCompleter, + Future? connectDebug, bool allowExistingDdsInstance = false, bool needsFullRestart = true, }) async { @@ -778,10 +788,8 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). } Uri? websocketUri; if (supportsServiceProtocol) { - final WebDevFS webDevFS = device!.devFS! as WebDevFS; - final bool useDebugExtension = - device!.device is WebServerDevice && debuggingOptions.startPaused; - _connectionResult = await webDevFS.connect(useDebugExtension); + assert(connectDebug != null); + _connectionResult = await connectDebug; unawaited(_connectionResult!.debugConnection!.onDone.whenComplete(_cleanupAndExit)); void onLogEvent(vmservice.Event event) { diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 2313ee3739e5b..e365921a049a6 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -66,7 +66,6 @@ Future generateLocalizations({ headerString: options.header, headerFile: options.headerFile, useDeferredLoading: options.useDeferredLoading, - useSyntheticPackage: options.syntheticPackage, areResourceAttributesRequired: options.requiredResourceAttributes, untranslatedMessagesFile: options.untranslatedMessagesFile, usesNullableGetter: options.nullableGetter, @@ -105,18 +104,6 @@ stderr:\n${result.stderr}''', result.exitCode); return generator; } -/// The path for the synthetic package. -String _defaultSyntheticPackagePath(FileSystem fileSystem) => - fileSystem.path.join('.dart_tool', 'flutter_gen'); - -/// The default path used when the `_useSyntheticPackage` setting is set to true -/// in [LocalizationsGenerator]. -/// -/// See [LocalizationsGenerator.new] for where and how it is used by the -/// localizations tool. -String _syntheticL10nPackagePath(FileSystem fileSystem) => - fileSystem.path.join(_defaultSyntheticPackagePath(fileSystem), 'gen_l10n'); - // Generate method parameters and also infer the correct types from the usage of the placeholders // For example, if placeholders are used for plurals and no type was specified, then the type will // automatically set to 'num'. Similarly, if such placeholders are used for selects, then the type @@ -545,7 +532,6 @@ class LocalizationsGenerator { String? headerFile, bool useDeferredLoading = false, String? inputsAndOutputsListPath, - bool useSyntheticPackage = false, String? projectPathString, bool areResourceAttributesRequired = false, String? untranslatedMessagesFile, @@ -562,15 +548,13 @@ class LocalizationsGenerator { inputPathString, projectDirectory, ); - final Directory outputDirectory = outputDirectoryFromPath( + final Directory outputDirectory = _outputDirectoryFromPath( fileSystem, outputPathString ?? inputPathString, - useSyntheticPackage, projectDirectory, ); return LocalizationsGenerator._( fileSystem, - useSyntheticPackage: useSyntheticPackage, usesNullableGetter: usesNullableGetter, className: classNameFromString(classNameString), projectDirectory: projectDirectory, @@ -612,7 +596,6 @@ class LocalizationsGenerator { this.header = '', this.useDeferredLoading = false, required this.inputsAndOutputsListFile, - this.useSyntheticPackage = true, this.projectDirectory, this.areResourceAttributesRequired = false, this.untranslatedMessagesFile, @@ -636,9 +619,6 @@ class LocalizationsGenerator { ); late final LocaleInfo _templateArbLocale = _templateBundle.locale; - @visibleForTesting - final bool useSyntheticPackage; - // Used to decide if the generated code is nullable or not // (whether AppLocalizations? or AppLocalizations is returned from // `static {name}Localizations{?} of (BuildContext context))` @@ -835,28 +815,16 @@ class LocalizationsGenerator { } /// Sets the reference [Directory] for [outputDirectory]. - @visibleForTesting - static Directory outputDirectoryFromPath( + static Directory _outputDirectoryFromPath( FileSystem fileSystem, String outputPathString, - bool useSyntheticPackage, Directory? projectDirectory, ) { - Directory outputDirectory; - if (useSyntheticPackage) { - outputDirectory = fileSystem.directory( - projectDirectory != null - ? _getAbsoluteProjectPath(_syntheticL10nPackagePath(fileSystem), projectDirectory) - : _syntheticL10nPackagePath(fileSystem), - ); - } else { - outputDirectory = fileSystem.directory( - projectDirectory != null - ? _getAbsoluteProjectPath(outputPathString, projectDirectory) - : outputPathString, - ); - } - return outputDirectory; + return fileSystem.directory( + projectDirectory != null + ? _getAbsoluteProjectPath(outputPathString, projectDirectory) + : outputPathString, + ); } /// Sets the reference [File] for [templateArbFile]. @@ -1469,22 +1437,6 @@ The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", " throw L10nException('Found syntax errors.'); } - // A pubspec.yaml file is required when using a synthetic package. If it does not - // exist, create a blank one. - if (useSyntheticPackage) { - final Directory syntheticPackageDirectory = - projectDirectory != null - ? projectDirectory!.childDirectory(_defaultSyntheticPackagePath(_fs)) - : _fs.directory(_defaultSyntheticPackagePath(_fs)); - syntheticPackageDirectory.createSync(recursive: true); - final File flutterGenPubspec = syntheticPackageDirectory.childFile('pubspec.yaml'); - if (!flutterGenPubspec.existsSync()) { - flutterGenPubspec.writeAsStringSync( - useCRLF ? emptyPubspecTemplate.replaceAll('\n', '\r\n') : emptyPubspecTemplate, - ); - } - } - // Since all validity checks have passed up to this point, // write the contents into the directory. outputDirectory.createSync(recursive: true); diff --git a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart index dfb291c3d70d8..b992c2231557d 100644 --- a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart +++ b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart @@ -8,7 +8,7 @@ import 'package:yaml/yaml.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; -import '../features.dart'; +import '../globals.dart' as globals; import '../runner/flutter_command.dart'; import 'gen_l10n_types.dart'; import 'language_subtag_registry.dart'; @@ -340,7 +340,6 @@ class LocalizationOptions { this.headerFile, bool? useDeferredLoading, this.genInputsAndOutputsList, - bool? syntheticPackage, this.projectDir, bool? requiredResourceAttributes, bool? nullableGetter, @@ -353,7 +352,6 @@ class LocalizationOptions { outputLocalizationFile = outputLocalizationFile ?? 'app_localizations.dart', outputClass = outputClass ?? 'AppLocalizations', useDeferredLoading = useDeferredLoading ?? false, - syntheticPackage = syntheticPackage ?? !featureFlags.isExplicitPackageDependenciesEnabled, requiredResourceAttributes = requiredResourceAttributes ?? false, nullableGetter = nullableGetter ?? true, format = format ?? true, @@ -415,12 +413,6 @@ class LocalizationOptions { /// This path is relative to [arbDir]. final String? genInputsAndOutputsList; - /// The `--synthetic-package` argument. - /// - /// Whether to generate the Dart localization files in a synthetic package - /// or in a custom directory. - final bool syntheticPackage; - /// The `--project-dir` argument. /// /// This path is relative to [arbDir]. @@ -481,7 +473,6 @@ LocalizationOptions parseLocalizationsOptionsFromYAML({ required Logger logger, required FileSystem fileSystem, required String defaultArbDir, - required bool defaultSyntheticPackage, }) { final String contents = file.readAsStringSync(); if (contents.trim().isEmpty) { @@ -497,6 +488,22 @@ LocalizationOptions parseLocalizationsOptionsFromYAML({ logger.printError('Expected ${file.path} to contain a map, instead was $yamlNode'); throw Exception(); } + const String kSyntheticPackage = 'synthetic-package'; + const String kFlutterGenNotice = 'http://flutter.dev/to/flutter-gen-deprecation'; + final bool? syntheticPackage = _tryReadBool(yamlNode, kSyntheticPackage, logger); + if (syntheticPackage != null) { + if (syntheticPackage) { + throwToolExit( + '${file.path}: Cannot enable "$kSyntheticPackage", this feature has ' + 'been removed. See $kFlutterGenNotice.', + ); + } else { + logger.printWarning( + '${file.path}: The argument "$kSyntheticPackage" no longer has any ' + 'effect and should be removed. See $kFlutterGenNotice', + ); + } + } return LocalizationOptions( arbDir: _tryReadFilePath(yamlNode, 'arb-dir', logger, fileSystem) ?? defaultArbDir, outputDir: _tryReadFilePath(yamlNode, 'output-dir', logger, fileSystem), @@ -518,8 +525,6 @@ LocalizationOptions parseLocalizationsOptionsFromYAML({ headerFile: _tryReadFilePath(yamlNode, 'header-file', logger, fileSystem), useDeferredLoading: _tryReadBool(yamlNode, 'use-deferred-loading', logger), preferredSupportedLocales: _tryReadStringList(yamlNode, 'preferred-supported-locales', logger), - syntheticPackage: - _tryReadBool(yamlNode, 'synthetic-package', logger) ?? defaultSyntheticPackage, requiredResourceAttributes: _tryReadBool(yamlNode, 'required-resource-attributes', logger), nullableGetter: _tryReadBool(yamlNode, 'nullable-getter', logger), format: _tryReadBool(yamlNode, 'format', logger), @@ -535,14 +540,20 @@ LocalizationOptions parseLocalizationsOptionsFromCommand({ required FlutterCommand command, required String defaultArbDir, }) { - // TODO(matanlurey): Remove as part of https://github.com/flutter/flutter/issues/102983. - final bool syntheticPackage; - if (command.argResults!.wasParsed('synthetic-package')) { - // If provided explicitly, use the explicit value. - syntheticPackage = command.boolArg('synthetic-package'); - } else { - // Otherwise, inherit from whatever the reverse of flutter config --explicit-package-dependencies. - syntheticPackage = !featureFlags.isExplicitPackageDependenciesEnabled; + const String kSyntheticPackage = 'synthetic-package'; + const String kFlutterGenNotice = 'http://flutter.dev/to/flutter-gen-deprecation'; + if (command.argResults!.wasParsed(kSyntheticPackage)) { + if (command.boolArg(kSyntheticPackage)) { + throwToolExit( + 'Cannot enable "$kSyntheticPackage", this feature has been removed. ' + 'See $kFlutterGenNotice.', + ); + } else { + globals.logger.printWarning( + 'The argument "$kSyntheticPackage" no longer has any effect and should ' + 'be removed. See $kFlutterGenNotice', + ); + } } return LocalizationOptions( arbDir: command.stringArg('arb-dir') ?? defaultArbDir, @@ -555,7 +566,6 @@ LocalizationOptions parseLocalizationsOptionsFromCommand({ headerFile: command.stringArg('header-file'), useDeferredLoading: command.boolArg('use-deferred-loading'), genInputsAndOutputsList: command.stringArg('gen-inputs-and-outputs-list'), - syntheticPackage: syntheticPackage, projectDir: command.stringArg('project-dir'), requiredResourceAttributes: command.boolArg('required-resource-attributes'), nullableGetter: command.boolArg('nullable-getter'), diff --git a/packages/flutter_tools/lib/src/macos/build_macos.dart b/packages/flutter_tools/lib/src/macos/build_macos.dart index 7d0e1405643fc..062ea5ce47e70 100644 --- a/packages/flutter_tools/lib/src/macos/build_macos.dart +++ b/packages/flutter_tools/lib/src/macos/build_macos.dart @@ -14,7 +14,6 @@ import '../base/terminal.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../convert.dart'; -import '../features.dart'; import '../globals.dart' as globals; import '../ios/migrations/metal_api_validation_migration.dart'; import '../ios/xcode_build_settings.dart'; @@ -149,7 +148,6 @@ Future buildMacOS({ await updateGeneratedXcodeProperties( project: flutterProject, buildInfo: buildInfo, - featureFlags: featureFlags, targetOverride: targetOverride, useMacOSConfig: true, ); diff --git a/packages/flutter_tools/lib/src/macos/swift_package_manager.dart b/packages/flutter_tools/lib/src/macos/swift_package_manager.dart index a77bd78b506c5..7b4a3f14c8dce 100644 --- a/packages/flutter_tools/lib/src/macos/swift_package_manager.dart +++ b/packages/flutter_tools/lib/src/macos/swift_package_manager.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import '../base/common.dart'; +import '../base/error_handling_io.dart'; import '../base/file_system.dart'; import '../base/template.dart'; import '../base/version.dart'; @@ -54,10 +55,19 @@ class SwiftPackageManager { ) async { _validatePlatform(platform); + final Directory symlinkDirectory = project.relativeSwiftPackagesDirectory; + ErrorHandlingFileSystem.deleteIfExists(symlinkDirectory, recursive: true); + symlinkDirectory.createSync(recursive: true); + final ( List packageDependencies, List targetDependencies, - ) = _dependenciesForPlugins(plugins, platform); + ) = _dependenciesForPlugins( + plugins: plugins, + platform: platform, + symlinkDirectory: symlinkDirectory, + pathRelativeTo: project.flutterPluginSwiftPackageDirectory.path, + ); // If there aren't any Swift Package plugins and the project hasn't been // migrated yet, don't generate a Swift package or migrate the app since @@ -100,10 +110,13 @@ class SwiftPackageManager { pluginsPackage.createSwiftPackage(); } - (List, List) _dependenciesForPlugins( - List plugins, - SupportedPlatform platform, - ) { + (List, List) + _dependenciesForPlugins({ + required List plugins, + required SupportedPlatform platform, + required Directory symlinkDirectory, + required String pathRelativeTo, + }) { final List packageDependencies = []; final List targetDependencies = []; @@ -113,18 +126,21 @@ class SwiftPackageManager { _fileSystem, platform.name, ); + String? packagePath = plugin.pluginSwiftPackagePath(_fileSystem, platform.name); if (plugin.platforms[platform.name] == null || pluginSwiftPackageManifestPath == null || + packagePath == null || !_fileSystem.file(pluginSwiftPackageManifestPath).existsSync()) { continue; } - packageDependencies.add( - SwiftPackagePackageDependency( - name: plugin.name, - path: _fileSystem.file(pluginSwiftPackageManifestPath).parent.path, - ), - ); + final Link pluginSymlink = symlinkDirectory.childLink(plugin.name); + ErrorHandlingFileSystem.deleteIfExists(pluginSymlink); + pluginSymlink.createSync(packagePath); + packagePath = pluginSymlink.path; + packagePath = _fileSystem.path.relative(packagePath, from: pathRelativeTo); + + packageDependencies.add(SwiftPackagePackageDependency(name: plugin.name, path: packagePath)); // The target dependency product name is hyphen separated because it's // the dependency's library name, which Swift Package Manager will diff --git a/packages/flutter_tools/lib/src/mdns_discovery.dart b/packages/flutter_tools/lib/src/mdns_discovery.dart index 975df2f8beb8e..659c44f89d9fa 100644 --- a/packages/flutter_tools/lib/src/mdns_discovery.dart +++ b/packages/flutter_tools/lib/src/mdns_discovery.dart @@ -597,7 +597,6 @@ class MDnsVmServiceDiscovery { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: case TargetPlatform.darwin: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index 0cbea601c4f67..af86b7043be47 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -438,14 +438,29 @@ class Plugin { /// Dev dependencies are intended to be stripped out in release builds. final bool isDevDependency; + /// Expected path to the plugin's swift package, which contains the Package.swift. + /// + /// This path should be `/path/to/[package_name]/[platform]/[package_name]` + /// (e.g. `/path/to/my_plugin/ios/my_plugin`). + /// + /// Returns null if the plugin does not support the [platform] or the + /// [platform] is not iOS or macOS. + String? pluginSwiftPackagePath(FileSystem fileSystem, String platform) { + final String? platformDirectoryName = _darwinPluginDirectoryName(platform); + if (platformDirectoryName == null) { + return null; + } + return fileSystem.path.join(path, platformDirectoryName, name); + } + /// Expected path to the plugin's Package.swift. Returns null if the plugin /// does not support the [platform] or the [platform] is not iOS or macOS. String? pluginSwiftPackageManifestPath(FileSystem fileSystem, String platform) { - final String? platformDirectoryName = _darwinPluginDirectoryName(platform); - if (platformDirectoryName == null) { + final String? packagePath = pluginSwiftPackagePath(fileSystem, platform); + if (packagePath == null) { return null; } - return fileSystem.path.join(path, platformDirectoryName, name, 'Package.swift'); + return fileSystem.path.join(packagePath, 'Package.swift'); } /// Expected path to the plugin's podspec. Returns null if the plugin does diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 941b2f83e4ef3..253b09da95686 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -222,11 +222,9 @@ class FlutterProject { /// The `.metadata` file of this project. File get metadataFile => directory.childFile('.metadata'); - /// The `.flutter-plugins` file of this project. - File get flutterPluginsFile => directory.childFile('.flutter-plugins'); - - /// The `.flutter-plugins-dependencies` file of this project, - /// which contains the dependencies each plugin depends on. + /// The `.flutter-plugins-dependencies` file of this project. + /// + /// Contains the dependencies each plugin depends on. File get flutterPluginsDependenciesFile => directory.childFile('.flutter-plugins-dependencies'); /// The `.gitignore` file of this project. diff --git a/packages/flutter_tools/lib/src/reporting/unified_analytics.dart b/packages/flutter_tools/lib/src/reporting/unified_analytics.dart index 1d490e3552e4b..a21be161beb7c 100644 --- a/packages/flutter_tools/lib/src/reporting/unified_analytics.dart +++ b/packages/flutter_tools/lib/src/reporting/unified_analytics.dart @@ -62,7 +62,7 @@ Analytics getAnalytics({ /// Uses the [Config] object to get enabled features. String? getEnabledFeatures(Config config) { // Create string with all enabled features to send as user property - final Iterable enabledFeatures = allFeatures.where((Feature feature) { + final Iterable enabledFeatures = featureFlags.allFeatures.where((Feature feature) { final String? configSetting = feature.configSetting; return configSetting != null && config.getValue(configSetting) == true; }); diff --git a/packages/flutter_tools/lib/src/reporting/usage.dart b/packages/flutter_tools/lib/src/reporting/usage.dart index 397552a5b7559..bdcbac5db5376 100644 --- a/packages/flutter_tools/lib/src/reporting/usage.dart +++ b/packages/flutter_tools/lib/src/reporting/usage.dart @@ -191,7 +191,7 @@ class _DefaultUsage implements Usage { ); // For each flutter experimental feature, record a session value in a comma // separated list. - final String enabledFeatures = allFeatures + final String enabledFeatures = featureFlags.allFeatures .where((Feature feature) { final String? configSetting = feature.configSetting; return configSetting != null && globals.config.getValue(configSetting) == true; diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 7d87339a6d1b7..db0ae602a607a 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -114,6 +114,12 @@ class FlutterDevice { globals.artifacts!.getHostArtifact(HostArtifact.webPlatformKernelFolder).path, platformDillName, ); + final List extraFrontEndOptions = [ + ...buildInfo.extraFrontEndOptions, + if (buildInfo.webEnableHotReload) + // These flags are only valid to be passed when compiling with DDC. + ...['--dartdevc-canary', '--dartdevc-module-format=ddc'], + ]; generator = ResidentCompiler( globals.artifacts!.getHostArtifact(HostArtifact.flutterWebSdk).path, @@ -133,7 +139,7 @@ class FlutterDevice { assumeInitializeFromDillUpToDate: buildInfo.assumeInitializeFromDillUpToDate, targetModel: TargetModel.dartdevc, frontendServerStarterPath: buildInfo.frontendServerStarterPath, - extraFrontEndOptions: buildInfo.extraFrontEndOptions, + extraFrontEndOptions: extraFrontEndOptions, platformDill: globals.fs.file(platformDillPath).absolute.uri.toString(), dartDefines: buildInfo.dartDefines, librariesSpec: @@ -1536,7 +1542,6 @@ Future getMissingPackageHintForPlatform(TargetPlatform platform) async case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: final FlutterProject project = FlutterProject.current(); final String manifestPath = globals.fs.path.relative(project.android.appManifestFile.path); return 'Is your project missing an $manifestPath?\nConsider running "flutter create ." to create one.'; diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 00f754f85914c..83db45bbd81ba 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -17,11 +17,9 @@ import '../base/io.dart'; import '../base/os.dart'; import '../base/utils.dart'; import '../build_info.dart'; -import '../build_system/build_system.dart'; import '../bundle.dart' as bundle; import '../cache.dart'; import '../convert.dart'; -import '../dart/generate_synthetic_packages.dart'; import '../dart/package_map.dart'; import '../dart/pub.dart'; import '../device.dart'; @@ -140,6 +138,7 @@ abstract final class FlutterOptions { static const String kAndroidGradleDaemon = 'android-gradle-daemon'; static const String kDeferredComponents = 'deferred-components'; static const String kAndroidProjectArgs = 'android-project-arg'; + static const String kAndroidGradleProjectCacheDir = 'android-project-cache-dir'; static const String kAndroidSkipBuildDependencyValidation = 'android-skip-build-dependency-validation'; static const String kInitializeFromDill = 'initialize-from-dill'; @@ -371,6 +370,7 @@ abstract class FlutterCommand extends Command { argParser.addFlag( FlutterOptions.kWebExperimentalHotReload, help: 'Enables new module format that supports hot reload.', + defaultsTo: true, hide: !verboseHelp, ); argParser.addOption( @@ -1069,6 +1069,10 @@ abstract class FlutterCommand extends Command { splitCommas: false, abbr: 'P', ); + argParser.addOption( + FlutterOptions.kAndroidGradleProjectCacheDir, + help: 'Specifies the project-specific cache directory. Defaults to .gradle.', + ); } void addNativeNullAssertions({bool hide = false}) { @@ -1327,10 +1331,9 @@ abstract class FlutterCommand extends Command { } // TODO(natebiggs): Delete this when new DDC module system is the default. - if (argParser.options.containsKey(FlutterOptions.kWebExperimentalHotReload) && - boolArg(FlutterOptions.kWebExperimentalHotReload)) { - extraFrontEndOptions.addAll(['--dartdevc-canary', '--dartdevc-module-format=ddc']); - } + final bool webEnableHotReload = + argParser.options.containsKey(FlutterOptions.kWebExperimentalHotReload) && + boolArg(FlutterOptions.kWebExperimentalHotReload); String? codeSizeDirectory; if (argParser.options.containsKey(FlutterOptions.kAnalyzeSize) && @@ -1369,6 +1372,11 @@ abstract class FlutterCommand extends Command { ? stringsArg(FlutterOptions.kAndroidProjectArgs) : []; + final String? androidGradleProjectCacheDir = + argParser.options.containsKey(FlutterOptions.kAndroidGradleProjectCacheDir) + ? stringArg(FlutterOptions.kAndroidGradleProjectCacheDir) + : null; + if (dartObfuscation && (splitDebugInfoPath == null || splitDebugInfoPath.isEmpty)) { throwToolExit( '"--${FlutterOptions.kDartObfuscationOption}" can only be used in ' @@ -1411,6 +1419,18 @@ abstract class FlutterCommand extends Command { final String? cliFlavor = argParser.options.containsKey('flavor') ? stringArg('flavor') : null; final String? flavor = cliFlavor ?? defaultFlavor; + if (globals.platform.environment[kAppFlavor] != null) { + throwToolExit('$kAppFlavor is used by the framework and cannot be set in the environment.'); + } + if (dartDefines.any((String define) => define.startsWith(kAppFlavor))) { + throwToolExit( + '$kAppFlavor is used by the framework and cannot be ' + 'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}', + ); + } + if (flavor != null) { + dartDefines.add('$kAppFlavor=$flavor'); + } _addFlutterVersionToDartDefines(globals.flutterVersion, dartDefines); return BuildInfo( @@ -1439,6 +1459,7 @@ abstract class FlutterCommand extends Command { androidSkipBuildDependencyValidation: androidSkipBuildDependencyValidation, packageConfig: packageConfig, androidProjectArgs: androidProjectArgs, + androidGradleProjectCacheDir: androidGradleProjectCacheDir, initializeFromDill: argParser.options.containsKey(FlutterOptions.kInitializeFromDill) ? stringArg(FlutterOptions.kInitializeFromDill) @@ -1447,6 +1468,7 @@ abstract class FlutterCommand extends Command { argParser.options.containsKey(FlutterOptions.kAssumeInitializeFromDillUpToDate) && boolArg(FlutterOptions.kAssumeInitializeFromDillUpToDate), useLocalCanvasKit: useLocalCanvasKit, + webEnableHotReload: webEnableHotReload, ); } @@ -1825,33 +1847,11 @@ abstract class FlutterCommand extends Command { project.checkForDeprecation(deprecationBehavior: deprecationBehavior); if (shouldRunPub) { - final Environment environment = Environment( - artifacts: globals.artifacts!, - logger: globals.logger, - cacheDir: globals.cache.getRoot(), - engineVersion: globals.flutterVersion.engineRevision, - fileSystem: globals.fs, - flutterRootDir: globals.fs.directory(Cache.flutterRoot), - outputDir: globals.fs.directory(getBuildDirectory()), - processManager: globals.processManager, - platform: globals.platform, - analytics: analytics, - projectDir: project.directory, - packageConfigPath: packageConfigPath(), - generateDartPluginRegistry: true, - ); - await pub.get( context: PubContext.getVerifyContext(name), project: project, checkUpToDate: cachePubGet, ); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: globals.buildSystem, - buildTargets: globals.buildTargets, - ); } if (regeneratePlatformSpecificToolingDuringVerify) { @@ -1899,9 +1899,7 @@ abstract class FlutterCommand extends Command { if (!shouldRunPub) { return; } - await project.regeneratePlatformSpecificTooling( - releaseMode: featureFlags.isExplicitPackageDependenciesEnabled && releaseMode, - ); + await project.regeneratePlatformSpecificTooling(releaseMode: releaseMode); } /// The set of development artifacts required for this command. @@ -2059,7 +2057,6 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) { case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x64: - case TargetPlatform.android_x86: return DevelopmentArtifact.androidGenSnapshot; case TargetPlatform.web_javascript: return DevelopmentArtifact.web; diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index aea3c00b93da6..48ff04969342c 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -283,7 +283,7 @@ class FlutterWebPlatform extends PlatformPlugin { // TODO(srujzs): Remove this assertion when the library bundle format is // supported without canary mode. if (buildInfo.ddcModuleFormat == DdcModuleFormat.ddc) { - assert(buildInfo.canaryFeatures ?? true); + assert(buildInfo.canaryFeatures); } final Map dartSdkArtifactMap = buildInfo.ddcModuleFormat == DdcModuleFormat.ddc @@ -296,7 +296,7 @@ class FlutterWebPlatform extends PlatformPlugin { // TODO(srujzs): Remove this assertion when the library bundle format is // supported without canary mode. if (buildInfo.ddcModuleFormat == DdcModuleFormat.ddc) { - assert(buildInfo.canaryFeatures ?? true); + assert(buildInfo.canaryFeatures); } final Map dartSdkArtifactMap = buildInfo.ddcModuleFormat == DdcModuleFormat.ddc diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 12a98f0b69d79..89eb65fcd7417 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -5,6 +5,7 @@ import 'package:package_config/package_config.dart'; import '../artifacts.dart'; +import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../build_info.dart'; @@ -197,14 +198,29 @@ interface class FlutterTestRunner { required FlutterProject flutterProject, required File isolateSpawningTesterPackageConfigFile, }) async { - final File projectPackageConfigFile = globals.fs + final File packageConfigFile = globals.fs .directory(flutterProject.directory.path) .childDirectory('.dart_tool') .childFile('package_config.json'); - final PackageConfig projectPackageConfig = PackageConfig.parseBytes( - projectPackageConfigFile.readAsBytesSync(), - projectPackageConfigFile.uri, - ); + PackageConfig? projectPackageConfig; + if (await packageConfigFile.exists()) { + projectPackageConfig = PackageConfig.parseBytes( + packageConfigFile.readAsBytesSync(), + Uri.file(flutterProject.directory.path), + ); + } else { + // We can't use this directly, but need to manually check + // `flutterProject.directory.path` first, as `findPackageConfig` is from a + // different package which does not use package:file. This inhibits + // mocking the file system. + projectPackageConfig = await findPackageConfig( + globals.fs.directory(flutterProject.directory.path), + ); + } + + if (projectPackageConfig == null) { + throwToolExit('Could not find package config for ${flutterProject.directory.path}.'); + } // The flutter_tools package_config.json is guaranteed to include // package:ffi and package:test_core. @@ -238,7 +254,6 @@ interface class FlutterTestRunner { required List packageTestArgs, required bool autoUpdateGoldenFiles, required File childTestIsolateSpawnerSourceFile, - required File childTestIsolateSpawnerDillFile, }) { final Map testConfigPaths = {}; @@ -659,7 +674,6 @@ class SpawnPlugin extends PlatformPlugin { packageTestArgs: packageTestArgs, autoUpdateGoldenFiles: updateGoldens, childTestIsolateSpawnerSourceFile: childTestIsolateSpawnerSourceFile, - childTestIsolateSpawnerDillFile: childTestIsolateSpawnerDillFile, ); _generateRootTestIsolateSpawnerSourceFile( diff --git a/packages/flutter_tools/lib/src/test/web_test_compiler.dart b/packages/flutter_tools/lib/src/test/web_test_compiler.dart index 1054cc4f8a72e..a8fceb5a6f3b8 100644 --- a/packages/flutter_tools/lib/src/test/web_test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/web_test_compiler.dart @@ -219,7 +219,7 @@ class WebTestCompiler { ), 'compile', 'wasm', - '--packages=.dart_tool/package_config.json', + '--packages=../../.dart_tool/package_config.json', '--extra-compiler-option=--platform=$platformFilePath', '--extra-compiler-option=--multi-root-scheme=org-dartlang-app', '--extra-compiler-option=--multi-root=${projectDirectory.childDirectory('test').path}', diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index 4902f732ea14d..4f6b56634c558 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -128,7 +128,7 @@ abstract class FlutterVersion { fetchTags: fetchTags, ); final String frameworkVersion = gitTagVersion.frameworkVersionFor(frameworkRevision); - return _FlutterVersionGit._( + final _FlutterVersionGit result = _FlutterVersionGit._( clock: clock, flutterRoot: flutterRoot, frameworkRevision: frameworkRevision, @@ -136,6 +136,10 @@ abstract class FlutterVersion { gitTagVersion: gitTagVersion, fs: fs, ); + if (fetchTags) { + result.ensureVersionFile(); + } + return result; } /// Ensure the latest git tags are fetched and recalculate [FlutterVersion]. diff --git a/packages/flutter_tools/lib/src/vscode/vscode.dart b/packages/flutter_tools/lib/src/vscode/vscode.dart index c4e7125a754c1..a920682cc1c66 100644 --- a/packages/flutter_tools/lib/src/vscode/vscode.dart +++ b/packages/flutter_tools/lib/src/vscode/vscode.dart @@ -68,10 +68,11 @@ class VsCode { String extensionDirectory, { String? edition, required FileSystem fileSystem, + required Platform platform, }) { final String packageJsonPath = fileSystem.path.join( installPath, - 'Resources', + platform.isLinux ? 'resources' : 'Resources', 'app', 'package.json', ); @@ -311,6 +312,7 @@ class VsCode { extensionDirectory, edition: searchLocation.edition, fileSystem: fileSystem, + platform: platform, ), ); } diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index 10d5757b4d89c..aeb19c7de3070 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -38,6 +38,7 @@ sealed class WebCompilerConfig { /// Returns which target this compiler outputs (js or wasm) CompileTarget get compileTarget; final WebRendererMode renderer; + List toCommandOptions(BuildMode buildMode); String get buildKey; @@ -92,10 +93,16 @@ class JsCompilerConfig extends WebCompilerConfig { CompileTarget get compileTarget => CompileTarget.js; /// Arguments to use in both phases: full JS compile and CFE-only. + /// + /// NOTE: MOST args should be passed here! List toSharedCommandOptions(BuildMode buildMode) => [ if (nativeNullAssertions) '--native-null-assertions', if (!sourceMaps) '--no-source-maps', if (buildMode == BuildMode.debug) '--enable-asserts', + '-O${optimizationLevelForBuildMode(buildMode)}', + if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', + if (noFrequencyBasedMinification) '--no-frequency-based-minification', + if (csp) '--csp', ]; @override @@ -111,14 +118,12 @@ class JsCompilerConfig extends WebCompilerConfig { /// Arguments to use in the full JS compile, but not CFE-only. /// - /// Includes the contents of [toSharedCommandOptions]. + /// Includes the contents of [toSharedCommandOptions]. That is where MOST + /// JS compiler flags should be passed! + @override List toCommandOptions(BuildMode buildMode) => [ - if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', ...toSharedCommandOptions(buildMode), - '-O${optimizationLevelForBuildMode(buildMode)}', if (dumpInfo) '--stage=dump-info-all', - if (noFrequencyBasedMinification) '--no-frequency-based-minification', - if (csp) '--csp', ]; @override @@ -130,7 +135,7 @@ class JsCompilerConfig extends WebCompilerConfig { 'nativeNullAssertions': nativeNullAssertions, 'noFrequencyBasedMinification': noFrequencyBasedMinification, 'minify': minify, - 'sourceMaps': sourceMaps, + WebCompilerConfig.kSourceMapsEnabled: sourceMaps, }; return jsonEncode(settings); } @@ -167,6 +172,7 @@ class WasmCompilerConfig extends WebCompilerConfig { BuildMode.jitRelease => throw ArgumentError('Invalid build mode for web'), }; + @override List toCommandOptions(BuildMode buildMode) { final bool stripSymbols = buildMode == BuildMode.release && stripWasm; return [ @@ -181,8 +187,8 @@ class WasmCompilerConfig extends WebCompilerConfig { String get buildKey { final Map settings = { ...super._buildKeyMap, - 'stripWasm': stripWasm, - 'sourceMaps': sourceMaps, + kStripWasm: stripWasm, + WebCompilerConfig.kSourceMapsEnabled: sourceMaps, }; return jsonEncode(settings); } diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart b/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart index da8605f645eb3..16a94c333f7a5 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_code_generator.dart @@ -198,6 +198,12 @@ class PreviewCodeGenerator { key: PreviewDetails.kBrightness, expression: preview.brightness, ), + ...?_generateCodeFromAnalyzerExpression( + allocator: allocator, + key: PreviewDetails.kLocalizations, + expression: preview.localizations, + isCallback: true, + ), _kBuilderProperty: previewWidget, }); } diff --git a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart index c7bb340895ddf..eeb3694bff779 100644 --- a/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart +++ b/packages/flutter_tools/lib/src/widget_preview/preview_detector.dart @@ -65,6 +65,7 @@ final class PreviewDetails { static const String kWrapper = 'wrapper'; static const String kTheme = 'theme'; static const String kBrightness = 'brightness'; + static const String kLocalizations = 'localizations'; /// The name of the function returning the preview. final String functionName; @@ -109,6 +110,9 @@ final class PreviewDetails { Expression? get brightness => _brightness; Expression? _brightness; + Expression? get localizations => _localizations; + Expression? _localizations; + void _setField({required NamedExpression node}) { final String key = node.name.label.name; final Expression expression = node.expression; @@ -125,6 +129,8 @@ final class PreviewDetails { _theme = expression as Identifier; case kBrightness: _brightness = expression; + case kLocalizations: + _localizations = expression; default: throw StateError('Unknown Preview field "$name": ${expression.toSource()}'); } @@ -144,14 +150,15 @@ final class PreviewDetails { other.textScaleFactor == textScaleFactor && other.wrapper == wrapper && other.theme == theme && - other.brightness == brightness; + other.brightness == brightness && + other.localizations == localizations; } @override String toString() => 'PreviewDetails(function: $functionName isBuilder: $isBuilder $kName: $name ' '$kSize: $size $kTextScaleFactor: $textScaleFactor $kWrapper: $wrapper ' - '$kTheme: $theme $kBrightness: $_brightness)'; + '$kTheme: $theme $kBrightness: $_brightness $kLocalizations: $_localizations)'; @override // ignore: avoid_equals_and_hash_code_on_mutable_classes @@ -163,6 +170,7 @@ final class PreviewDetails { wrapper, theme, brightness, + localizations, ]); } diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index 8e9c98a884d7e..433ee9720777e 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -139,13 +139,20 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform { /// checked in should live here. Directory get ephemeralDirectory => managedDirectory.childDirectory('ephemeral'); - /// The Flutter generated directory for the Swift Package handling plugin + /// The Flutter generated directory for generated Swift packages. + Directory get flutterSwiftPackagesDirectory => ephemeralDirectory.childDirectory('Packages'); + + /// Flutter plugins that support SwiftPM will be symlinked in this directory to keep all + /// Swift packages relative to each other. + Directory get relativeSwiftPackagesDirectory => + flutterSwiftPackagesDirectory.childDirectory('.packages'); + + /// The Flutter generated directory for the Swift package handling plugin /// dependencies. - Directory get flutterPluginSwiftPackageDirectory => ephemeralDirectory - .childDirectory('Packages') - .childDirectory(kFlutterGeneratedPluginSwiftPackageName); + Directory get flutterPluginSwiftPackageDirectory => + flutterSwiftPackagesDirectory.childDirectory(kFlutterGeneratedPluginSwiftPackageName); - /// The Flutter generated Swift Package manifest (Package.swift) for plugin + /// The Flutter generated Swift package manifest (Package.swift) for plugin /// dependencies. File get flutterPluginSwiftPackageManifest => flutterPluginSwiftPackageDirectory.childFile('Package.swift'); @@ -436,6 +443,10 @@ def __lldb_init_module(debugger: lldb.SBDebugger, _): File get appDelegateSwift => _editableDirectory.childDirectory('Runner').childFile('AppDelegate.swift'); + /// The 'AppDelegate.m' file of the host app. This file might not exist if the app project uses Swift. + File get appDelegateObjc => + _editableDirectory.childDirectory('Runner').childFile('AppDelegate.m'); + File get infoPlist => _editableDirectory.childDirectory('Runner').childFile('Info.plist'); Directory get symlinks => _flutterLibRoot.childDirectory('.symlinks'); @@ -755,7 +766,6 @@ def __lldb_init_module(debugger: lldb.SBDebugger, _): await xcode.updateGeneratedXcodeProperties( project: parent, buildInfo: BuildInfo.dummy, - featureFlags: featureFlags, targetOverride: bundle.defaultMainPath, ); } @@ -972,7 +982,6 @@ class MacOSProject extends XcodeBasedProject { await xcode.updateGeneratedXcodeProperties( project: parent, buildInfo: BuildInfo.dummy, - featureFlags: featureFlags, useMacOSConfig: true, ); } diff --git a/packages/flutter_tools/pubspec.lock b/packages/flutter_tools/pubspec.lock new file mode 100644 index 0000000000000..f6e3c5e518e20 --- /dev/null +++ b/packages/flutter_tools/pubspec.lock @@ -0,0 +1,797 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: "direct main" + description: + name: _fe_analyzer_shared + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f + url: "https://pub.dev" + source: hosted + version: "82.0.0" + analyzer: + dependency: "direct main" + description: + name: analyzer + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" + url: "https://pub.dev" + source: hosted + version: "7.4.5" + archive: + dependency: "direct main" + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: "direct main" + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: "direct main" + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: "direct main" + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + browser_launcher: + dependency: "direct main" + description: + name: browser_launcher + sha256: ca2557663d3033845f2ef2b60f94fc249528324fd1affddccb7c63ac0ccd6c67 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + built_collection: + dependency: "direct main" + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: "direct main" + description: + name: built_value + sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27" + url: "https://pub.dev" + source: hosted + version: "8.10.1" + checked_yaml: + dependency: "direct dev" + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_config: + dependency: "direct main" + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + clock: + dependency: "direct main" + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: "direct main" + description: + name: code_assets + sha256: "2d1f99d221a174275a7992152039264dcb69521bb61fb541544187b0eeeda018" + url: "https://pub.dev" + source: hosted + version: "0.19.0" + code_builder: + dependency: "direct main" + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" + collection: + dependency: "direct dev" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + completion: + dependency: "direct main" + description: + name: completion + sha256: f11b7a628e6c42b9edc9b0bc3aa490e2d930397546d2f794e8e1325909d11c60 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + convert: + dependency: "direct main" + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: "direct main" + description: + name: coverage + sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 + url: "https://pub.dev" + source: hosted + version: "1.14.1" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + csslib: + dependency: "direct main" + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + dap: + dependency: "direct main" + description: + name: dap + sha256: "42b0b083a09c59a118741769e218fc3738980ab591114f09d1026241d2b9c290" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + dart_style: + dependency: "direct main" + description: + name: dart_style + sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + dds: + dependency: "direct main" + description: + name: dds + sha256: "76fc5140ce4e8922711bbe6dfd3713283ecc7f386c52fc7f594cd5f3e6b80633" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + dds_service_extensions: + dependency: "direct main" + description: + name: dds_service_extensions + sha256: c514114300ab30a95903fed1fdcf2949d057a0ea961168ec890a2b415b3ec52a + url: "https://pub.dev" + source: hosted + version: "2.0.2" + devtools_shared: + dependency: "direct main" + description: + name: devtools_shared + sha256: "659e2d65aa5ef5c3551163811c5c6fa1b973b3df80d8cac6f618035edcdc1096" + url: "https://pub.dev" + source: hosted + version: "11.2.1" + dtd: + dependency: "direct main" + description: + name: dtd + sha256: "14a0360d898ded87c3d99591fc386b8a6ea5d432927bee709b22130cd25b993a" + url: "https://pub.dev" + source: hosted + version: "2.5.1" + dwds: + dependency: "direct main" + description: + name: dwds + sha256: "063ca26b035fa80b7b66664d9efbc5d2acb45e139a452d59b0fe6df61a96f443" + url: "https://pub.dev" + source: hosted + version: "24.3.10" + extension_discovery: + dependency: "direct main" + description: + name: extension_discovery + sha256: de1fce715ab013cdfb00befc3bdf0914bea5e409c3a567b7f8f144bc061611a7 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + fake_async: + dependency: "direct main" + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + file: + dependency: "direct main" + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_testing: + dependency: "direct dev" + description: + name: file_testing + sha256: eb0c85fd118ddc0d41c295c09f64e0924c256b071087cdc9828d5372c80d554d + url: "https://pub.dev" + source: hosted + version: "3.0.2" + fixnum: + dependency: "direct main" + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_template_images: + dependency: "direct main" + description: + name: flutter_template_images + sha256: "0120589a786dbae4e86af1f61748baccd8530abd56a60e7a13479647a75222fe" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + frontend_server_client: + dependency: "direct main" + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: "direct main" + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: "direct main" + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + hooks: + dependency: "direct main" + description: + name: hooks + sha256: c29b5d113b093995426c9d2d4ce157902f04d426d9fb44206f88d2da7ae3e0f2 + url: "https://pub.dev" + source: hosted + version: "0.19.1" + hooks_runner: + dependency: "direct main" + description: + name: hooks_runner + sha256: a0f1aa2ef80eb8a9c5d8335d613c0a16d0a3b038098151430ce2e884804244ca + url: "https://pub.dev" + source: hosted + version: "0.20.0" + html: + dependency: "direct main" + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" + http: + dependency: "direct main" + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + http_multi_server: + dependency: "direct main" + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: "direct main" + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + io: + dependency: "direct main" + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + js: + dependency: "direct dev" + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + json_annotation: + dependency: "direct dev" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_rpc_2: + dependency: "direct main" + description: + name: json_rpc_2 + sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + logging: + dependency: "direct main" + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: "direct main" + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + meta: + dependency: "direct main" + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + mime: + dependency: "direct main" + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + multicast_dns: + dependency: "direct main" + description: + name: multicast_dns + sha256: de72ada5c3db6fdd6ad4ae99452fe05fb403c4bb37c67ceb255ddd37d2b5b1eb + url: "https://pub.dev" + source: hosted + version: "0.3.3" + mustache_template: + dependency: "direct main" + description: + name: mustache_template + sha256: a46e26f91445bfb0b60519be280555b06792460b27b19e2b19ad5b9740df5d1c + url: "https://pub.dev" + source: hosted + version: "2.0.0" + native_stack_traces: + dependency: "direct main" + description: + name: native_stack_traces + sha256: d34cf916db87b14d39465b3e3b4b4a8ee1f304bde6ed7605571e34802e3d6a11 + url: "https://pub.dev" + source: hosted + version: "0.6.1" + node_preamble: + dependency: "direct dev" + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: "direct main" + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: "direct main" + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + platform: + dependency: "direct main" + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + pool: + dependency: "direct main" + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process: + dependency: "direct main" + description: + name: process + sha256: "44b4226c0afd4bc3b7c7e67d44c4801abd97103cf0c84609e2654b664ca2798c" + url: "https://pub.dev" + source: hosted + version: "5.0.4" + pub_semver: + dependency: "direct main" + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: "direct main" + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + shelf: + dependency: "direct main" + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: "direct main" + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_proxy: + dependency: "direct main" + description: + name: shelf_proxy + sha256: a71d2307f4393211930c590c3d2c00630f6c5a7a77edc1ef6436dfd85a6a7ee3 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + shelf_static: + dependency: "direct main" + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: "direct main" + description: + name: shelf_web_socket + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + source_map_stack_trace: + dependency: "direct main" + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: "direct main" + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + sprintf: + dependency: "direct main" + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sse: + dependency: "direct main" + description: + name: sse + sha256: fcc97470240bb37377f298e2bd816f09fd7216c07928641c0560719f50603643 + url: "https://pub.dev" + source: hosted + version: "4.1.8" + stack_trace: + dependency: "direct main" + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + standard_message_codec: + dependency: "direct main" + description: + name: standard_message_codec + sha256: fc7dd712d191b7e33196a0ecf354c4573492bb95995e7166cb6f73b047f9cae0 + url: "https://pub.dev" + source: hosted + version: "0.0.1+4" + stream_channel: + dependency: "direct main" + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: "direct main" + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + sync_http: + dependency: "direct main" + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: "direct main" + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" + url: "https://pub.dev" + source: hosted + version: "1.26.2" + test_api: + dependency: "direct main" + description: + name: test_api + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + test_core: + dependency: "direct main" + description: + name: test_core + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" + url: "https://pub.dev" + source: hosted + version: "0.6.11" + typed_data: + dependency: "direct main" + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + unified_analytics: + dependency: "direct main" + description: + name: unified_analytics + sha256: c8abdcad84b55b78f860358aae90077b8f54f98169a75e16d97796a1b3c95590 + url: "https://pub.dev" + source: hosted + version: "8.0.1" + usage: + dependency: "direct main" + description: + name: usage + sha256: "0bdbde65a6e710343d02a56552eeaefd20b735e04bfb6b3ee025b6b22e8d0e15" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" + vm_service: + dependency: "direct main" + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + vm_service_interface: + dependency: "direct main" + description: + name: vm_service_interface + sha256: "503c92c26cf9f77d688bf8fca27fa9ec40450adbf02ec1ec5f12828ded508ac0" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + vm_snapshot_analysis: + dependency: "direct main" + description: + name: vm_snapshot_analysis + sha256: "5a79b9fbb6be2555090f55b03b23907e75d44c3fd7bdd88da09848aa5a1914c8" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + watcher: + dependency: "direct main" + description: + name: watcher + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web: + dependency: "direct main" + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: "direct main" + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webdriver: + dependency: "direct main" + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + webkit_inspection_protocol: + dependency: "direct main" + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + xml: + dependency: "direct main" + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" + yaml_edit: + dependency: "direct main" + description: + name: yaml_edit + sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5 + url: "https://pub.dev" + source: hosted + version: "2.2.2" +sdks: + dart: ">=3.9.0-21.0.dev <4.0.0" diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 73287243d29c4..aa999fa7c22c1 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: dwds: 24.3.10 code_builder: 4.10.1 completion: 1.0.1 - coverage: 1.13.1 + coverage: 1.14.1 crypto: 3.0.6 ffi: 2.1.4 file: 7.0.1 @@ -24,11 +24,11 @@ dependencies: html: 0.15.6 http: 1.4.0 intl: 0.20.2 - meta: 1.16.0 + meta: 1.17.0 multicast_dns: 0.3.3 mustache_template: 2.0.0 package_config: 2.2.0 - process: 5.0.3 + process: 5.0.4 fake_async: 1.3.3 stack_trace: 1.12.1 usage: 4.1.1 @@ -36,7 +36,7 @@ dependencies: webkit_inspection_protocol: 1.2.1 xml: 6.5.0 yaml: 3.1.3 - native_stack_traces: 0.6.0 + native_stack_traces: 0.6.1 shelf: 1.4.2 vm_snapshot_analysis: 0.7.6 uuid: 4.5.1 @@ -53,6 +53,7 @@ dependencies: convert: 3.1.2 async: 2.13.0 unified_analytics: 8.0.1 + pubspec_parse: 1.5.0 graphs: 2.3.2 hooks_runner: 0.20.0 @@ -63,67 +64,67 @@ dependencies: # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. test_api: 0.7.6 - test_core: 0.6.10 + test_core: 0.6.11 - vm_service: 15.0.0 + vm_service: 15.0.2 standard_message_codec: 0.0.1+4 dart_style: 3.1.0 - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - browser_launcher: 1.1.3 # 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.9.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - csslib: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dap: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dds_service_extensions: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - devtools_shared: 11.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dtd: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - extension_discovery: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fixnum: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_rpc_2: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_proxy: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - sprintf: 7.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - sse: 4.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml_edit: 2.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + # The below dependencies are transitive and are here to pin them to a specific version. + _fe_analyzer_shared: 82.0.0 + analyzer: 7.4.5 + boolean_selector: 2.1.2 + browser_launcher: 1.1.3 + built_collection: 5.1.1 + built_value: 8.10.1 + cli_config: 0.2.0 + clock: 1.1.2 + csslib: 1.0.2 + dap: 1.4.0 + dds_service_extensions: 2.0.2 + devtools_shared: 11.2.1 + dtd: 2.5.1 + extension_discovery: 2.1.0 + fixnum: 1.1.1 + frontend_server_client: 4.0.0 + glob: 2.1.3 + http_parser: 4.1.2 + io: 1.0.5 + json_rpc_2: 3.0.3 + matcher: 0.12.17 + petitparser: 6.1.0 + platform: 3.1.6 + shelf_packages_handler: 3.0.2 + shelf_proxy: 1.0.4 + source_map_stack_trace: 2.1.2 + source_maps: 0.10.13 + source_span: 1.10.1 + sprintf: 7.0.0 + sse: 4.1.8 + string_scanner: 1.4.1 + sync_http: 0.3.1 + term_glyph: 1.2.2 + typed_data: 1.4.0 + vm_service_interface: 2.0.1 + watcher: 1.1.1 + web: 1.1.1 + web_socket: 1.0.1 + yaml_edit: 2.2.2 dev_dependencies: collection: 1.19.1 file_testing: 3.0.2 - pubspec_parse: 1.5.0 - checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_annotation: 4.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + checked_yaml: 2.0.4 + js: 0.7.2 + json_annotation: 4.9.0 + node_preamble: 2.0.2 + test: 1.26.2 dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: eaa1 +# PUBSPEC CHECKSUM: 3ino33 diff --git a/packages/flutter_tools/templates/app/.gitignore.tmpl b/packages/flutter_tools/templates/app/.gitignore.tmpl index ba6d23804e94b..3820a95c65c3e 100644 --- a/packages/flutter_tools/templates/app/.gitignore.tmpl +++ b/packages/flutter_tools/templates/app/.gitignore.tmpl @@ -27,7 +27,6 @@ migrate_working_dir/ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .pub-cache/ .pub/ diff --git a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl index bb6ce2f4c44a4..71c25ff83afdb 100644 --- a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl +++ b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl @@ -45,5 +45,26 @@ UIApplicationSupportsIndirectInputEvents + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/packages/flutter_tools/templates/module/common/.gitignore.tmpl b/packages/flutter_tools/templates/module/common/.gitignore.tmpl index 525e05cfbaf9e..5d88593fb3b98 100644 --- a/packages/flutter_tools/templates/module/common/.gitignore.tmpl +++ b/packages/flutter_tools/templates/module/common/.gitignore.tmpl @@ -39,7 +39,6 @@ Icon? build/ .android/ .ios/ -.flutter-plugins .flutter-plugins-dependencies # Symbolication related diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl index a4388efddd1b1..fdd4b92c6ea56 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl @@ -45,5 +45,26 @@ UIApplicationSupportsIndirectInputEvents + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/packages/flutter_tools/templates/package/.gitignore.tmpl b/packages/flutter_tools/templates/package/.gitignore.tmpl index 878e781b635ae..dd5eb98951f29 100644 --- a/packages/flutter_tools/templates/package/.gitignore.tmpl +++ b/packages/flutter_tools/templates/package/.gitignore.tmpl @@ -26,7 +26,6 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies /build/ /coverage/ diff --git a/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl b/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl index 9f974de2dc4c8..74ab49d584a94 100644 --- a/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl +++ b/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl @@ -26,7 +26,6 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages /build/ diff --git a/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl b/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl index a55c31c17fac9..b9d7f25b91b64 100644 --- a/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl +++ b/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl @@ -28,7 +28,6 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies /build/ /coverage/ diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl index 641c2fbdf9681..00f480eb8cd75 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl @@ -74,13 +74,13 @@ class ZoomControls extends StatelessWidget { void _zoomIn() { _transformationController.value = Matrix4.copy( _transformationController.value, - ).scaled(1.1); + ).scaledByDouble(1.1, 1.1, 1.1, 1); } void _zoomOut() { final Matrix4 updated = Matrix4.copy( _transformationController.value, - ).scaled(0.9); + ).scaledByDouble(0.9, 0.9, 0.9, 1); // Don't allow for zooming out past the original size of the widget. // Assumes scaling is evenly applied to the entire matrix. diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview.dart.tmpl index 12c4975356171..8e4494a6c5f27 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview.dart.tmpl @@ -28,6 +28,7 @@ class WidgetPreview { this.textScaleFactor, this.brightness, this.theme, + this.localizations, }); /// A description to be displayed alongside the preview. @@ -63,12 +64,25 @@ class WidgetPreview { /// If not provided, the current system default brightness will be used. final Brightness? brightness; + /// A callback to return a localization configuration to be applied to the + /// previewed [Widget]. + /// + /// Note: this must be a reference to a static, public function defined as + /// either a top-level function or static member in a class. + final PreviewLocalizationsData? localizations; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { properties ..add(DiagnosticsProperty('name', name, ifNull: 'not set')) ..add(DiagnosticsProperty('size', size)) ..add(DiagnosticsProperty('textScaleFactor', textScaleFactor)) ..add(DiagnosticsProperty('theme', theme)) - ..add(DiagnosticsProperty('brightness', brightness)); + ..add(DiagnosticsProperty('brightness', brightness)) + ..add( + DiagnosticsProperty( + 'localizations', + localizations, + ), + ); } } diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl index 347c24915d0c3..ee1cdbd1b5583 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl @@ -322,6 +322,11 @@ class WidgetPreviewWidgetState extends State { child: preview, ); + preview = WidgetPreviewLocalizations( + localizationsData: widget.preview.localizations, + child: preview, + ); + preview = Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -472,6 +477,72 @@ class WidgetPreviewMediaQueryOverride extends StatelessWidget { } } +/// Wraps [child] with a [Localizations] with localization data from +/// [localizationsData]. +class WidgetPreviewLocalizations extends StatefulWidget { + const WidgetPreviewLocalizations({ + super.key, + required this.localizationsData, + required this.child, + }); + + final PreviewLocalizationsData? localizationsData; + final Widget child; + + @override + State createState() => + _WidgetPreviewLocalizationsState(); +} + +class _WidgetPreviewLocalizationsState + extends State { + PreviewLocalizationsData get _localizationsData => widget.localizationsData!; + late final LocalizationsResolver _localizationsResolver = + LocalizationsResolver( + supportedLocales: _localizationsData.supportedLocales, + locale: _localizationsData.locale, + localeListResolutionCallback: + _localizationsData.localeListResolutionCallback, + localeResolutionCallback: _localizationsData.localeResolutionCallback, + localizationsDelegates: _localizationsData.localizationsDelegates, + ); + + @override + void didUpdateWidget(WidgetPreviewLocalizations oldWidget) { + super.didUpdateWidget(oldWidget); + final PreviewLocalizationsData? localizationsData = + widget.localizationsData; + if (localizationsData == null) { + return; + } + _localizationsResolver.update( + supportedLocales: localizationsData.supportedLocales, + locale: localizationsData.locale, + localeListResolutionCallback: + localizationsData.localeListResolutionCallback, + localeResolutionCallback: localizationsData.localeResolutionCallback, + localizationsDelegates: localizationsData.localizationsDelegates, + ); + } + + @override + Widget build(BuildContext context) { + if (widget.localizationsData == null) { + return widget.child; + } + return ListenableBuilder( + listenable: _localizationsResolver, + builder: (context, _) { + return Localizations( + locale: _localizationsResolver.locale, + delegates: _localizationsResolver.localizationsDelegates.toList(), + child: widget.child, + ); + }, + ); + } +} + /// An [InheritedWidget] that propagates the current size of the /// WidgetPreviewScaffold. /// 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 57dd06dc8114b..e67b699fbf1da 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 @@ -400,7 +400,7 @@ void main() { ); testUsingContext( - 'Defaults to web renderer canvaskit mode when no option is specified', + 'Defaults to web renderer canvaskit and minify mode when no option is specified', () async { final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); final CommandRunner runner = createTestCommandRunner(buildCommand); @@ -419,8 +419,17 @@ void main() { ) { expect(target, isA()); final List configs = (target as WebServiceWorker).compileConfigs; - expect(configs.length, 1); - expect(configs.first.renderer, WebRendererMode.canvaskit); + expect(configs, hasLength(1)); + final WebCompilerConfig config = configs.single; + expect(config.renderer, WebRendererMode.canvaskit); + expect(config.compileTarget, CompileTarget.js); + final List options = config.toCommandOptions(BuildMode.release); + expect(options, [ + '--native-null-assertions', + '--no-source-maps', + '-O4', + '--minify', + ]); }), }, ); @@ -445,7 +454,7 @@ void main() { ) { expect(target, isA()); final List configs = (target as WebServiceWorker).compileConfigs; - expect(configs.length, 2); + expect(configs, hasLength(2)); expect(configs[0].renderer, WebRendererMode.skwasm); expect(configs[0].compileTarget, CompileTarget.wasm); expect(configs[1].renderer, WebRendererMode.canvaskit); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/clean_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/clean_test.dart index 0989118fcdc7b..3cfbe6d5180c8 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/clean_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/clean_test.dart @@ -5,6 +5,7 @@ import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/base/error_handling_io.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -76,7 +77,6 @@ void main() { expect(projectUnderTest.macos.flutterPluginSwiftPackageDirectory, isNot(exists)); expect(projectUnderTest.windows.ephemeralDirectory, isNot(exists)); - expect(projectUnderTest.flutterPluginsFile, isNot(exists)); expect(projectUnderTest.flutterPluginsDependenciesFile, isNot(exists)); expect( projectUnderTest.directory @@ -235,7 +235,13 @@ void main() { '$CleanCommand handles missing delete permissions', () async { final FileExceptionHandler handler = FileExceptionHandler(); - final FileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); + + // Ensures we handle ErrorHandlingFileSystem appropriately in prod. + // See https://github.com/flutter/flutter/issues/108978. + final FileSystem fileSystem = ErrorHandlingFileSystem( + delegate: MemoryFileSystem.test(opHandle: handler.opHandle), + platform: windowsPlatform, + ); final File throwingFile = fileSystem.file('bad')..createSync(); handler.addError( throwingFile, @@ -291,7 +297,6 @@ FlutterProject setupProjectUnderTest(Directory currentDirectory, bool setupXcode projectUnderTest.macos.ephemeralDirectory.createSync(recursive: true); projectUnderTest.macos.flutterPluginSwiftPackageDirectory.createSync(recursive: true); projectUnderTest.windows.ephemeralDirectory.createSync(recursive: true); - projectUnderTest.flutterPluginsFile.createSync(recursive: true); projectUnderTest.flutterPluginsDependenciesFile.createSync(recursive: true); return projectUnderTest; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart index 18745650d532d..2a061d03374f6 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart @@ -54,7 +54,7 @@ void main() { expect( testLogger.statusText, 'All Settings:\n' - '${allFeatures.where((Feature e) => e.configSetting != null).map((Feature e) => ' ${e.configSetting}: (Not set)').join('\n')}' + '${featureFlags.allFeatures.where((Feature e) => e.configSetting != null).map((Feature e) => ' ${e.configSetting}: (Not set)').join('\n')}' '\n\n', ); }); 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 dfddc525145ee..210bca97ba3fd 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 @@ -33,11 +33,10 @@ class FakePub extends Fake implements Pub { required FlutterProject project, bool upgrade = false, bool offline = false, - bool generateSyntheticPackage = false, - bool generateSyntheticPackageForExample = false, String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async { writePackageConfigFiles(directory: project.directory, mainLibName: 'my_app'); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart index 1b54e40560af7..9e8174e6a8d59 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart @@ -1428,6 +1428,7 @@ class VsCodeValidatorTestTargets extends VsCodeValidator { extensionDirectory, edition: edition, fileSystem: globals.fs, + platform: globals.platform, ), ); 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 64c3bdd030d68..6711d69b8e235 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -928,10 +928,10 @@ class FakePub extends Fake implements Pub { required FlutterProject project, bool upgrade = false, bool offline = false, - bool generateSyntheticPackage = false, String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async {} } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/flutter_web_platform_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/flutter_web_platform_test.dart index 94f72f49ba1e7..75146b19884ea 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/flutter_web_platform_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/flutter_web_platform_test.dart @@ -133,6 +133,7 @@ void main() { packageConfigPath: '.dart_tool/package_config.json', treeShakeIcons: false, extraFrontEndOptions: ['--dartdevc-module-format=ddc', '--canary'], + webEnableHotReload: true, ), webMemoryFS: WebMemoryFS(), fileSystem: fileSystem, 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 c961c7eec5b3c..ce2dc90ecef23 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 @@ -69,76 +69,6 @@ void main() { }, ); - testUsingContext( - 'not using synthetic packages (explicitly)', - () async { - final Directory l10nDirectory = fileSystem.directory(fileSystem.path.join('lib', 'l10n')); - final File arbFile = l10nDirectory.childFile('app_en.arb')..createSync(recursive: true); - - arbFile.writeAsStringSync(''' -{ - "helloWorld": "Hello, World!", - "@helloWorld": { - "description": "Sample description" - } -}'''); - fileSystem.file('pubspec.yaml').writeAsStringSync(''' -flutter: - generate: true'''); - - final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( - fileSystem: fileSystem, - logger: logger, - artifacts: artifacts, - processManager: processManager, - ); - await createTestCommandRunner(command).run(['gen-l10n', '--no-synthetic-package']); - - expect(l10nDirectory.existsSync(), true); - expect(l10nDirectory.childFile('app_localizations_en.dart').existsSync(), true); - expect(l10nDirectory.childFile('app_localizations.dart').existsSync(), true); - }, - overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - }, - ); - - testUsingContext( - 'not using synthetic packages (due to --explicit-package-dependencies)', - () async { - final Directory l10nDirectory = fileSystem.directory(fileSystem.path.join('lib', 'l10n')); - final File arbFile = l10nDirectory.childFile('app_en.arb')..createSync(recursive: true); - - arbFile.writeAsStringSync(''' -{ - "helloWorld": "Hello, World!", - "@helloWorld": { - "description": "Sample description" - } -}'''); - fileSystem.file('pubspec.yaml').writeAsStringSync(''' -flutter: - generate: true'''); - - final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( - fileSystem: fileSystem, - logger: logger, - artifacts: artifacts, - processManager: processManager, - ); - await createTestCommandRunner(command).run(['gen-l10n']); - - expect(l10nDirectory.existsSync(), true); - expect(l10nDirectory.childFile('app_localizations_en.dart').existsSync(), true); - expect(l10nDirectory.childFile('app_localizations.dart').existsSync(), true); - }, - overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - }, - ); - testUsingContext( 'throws error when arguments are invalid', () async { @@ -590,7 +520,7 @@ format: false ); testUsingContext( - 'throw when generate: false and uses synthetic package when run with l10n.yaml', + 'throw when generate: false when run with l10n.yaml', () async { final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); @@ -636,7 +566,7 @@ format: false ); testUsingContext( - 'throw when generate: false and uses synthetic package when run via commandline options', + 'throw when generate: false when run via commandline options', () async { final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); @@ -667,8 +597,7 @@ format: false processManager: processManager, ); expect( - () async => - createTestCommandRunner(command).run(['gen-l10n', '--synthetic-package']), + () async => createTestCommandRunner(command).run(['gen-l10n']), throwsToolExit( message: 'Attempted to generate localizations code without having the flutter: generate flag turned on.', @@ -689,13 +618,44 @@ format: false processManager: processManager, ); expect( - () async => createTestCommandRunner( - command, - ).run(['gen-l10n', '--synthetic-package', 'false']), + () async => createTestCommandRunner(command).run(['gen-l10n', 'false']), throwsToolExit(message: 'Unexpected positional argument "false".'), ); }); + testUsingContext('throws error when synthetic-package is provided', () async { + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + await expectLater( + () async => createTestCommandRunner(command).run(['gen-l10n', '--synthetic-package']), + throwsToolExit(message: 'synthetic-package'), + ); + }); + + testUsingContext( + 'prints warning when --no-synthetic-package is provided', + () async { + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + fileSystem + .file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) + .createSync(recursive: true); + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + pubspecFile.writeAsStringSync(BasicProjectWithFlutterGen().pubspec); + await createTestCommandRunner(command).run(['gen-l10n', '--no-synthetic-package']); + expect(logger.warningText, contains('synthetic-package')); + }, + overrides: {Logger: () => logger}, + ); + group(AppResourceBundle, () { testWithoutContext("can be parsed without FormatException when it's content is empty", () { final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) diff --git a/packages/flutter_tools/test/commands.shard/hermetic/pub_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/pub_test.dart index 7262cbbce8327..57403bba9f9c8 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/pub_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/pub_test.dart @@ -11,14 +11,11 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/packages.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/project.dart'; -import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:test/fake.dart'; import 'package:unified_analytics/unified_analytics.dart'; import '../../src/context.dart'; -import '../../src/fakes.dart'; import '../../src/package_config.dart'; import '../../src/test_flutter_command_runner.dart'; @@ -38,15 +35,6 @@ void main() { late FakePub pub; late BufferLogger logger; - // TODO(matanlurey): Remove after `flutter_gen` is removed. - // See https://github.com/flutter/flutter/issues/102983 for details. - FeatureFlags disableExplicitPackageDependencies() { - return TestFeatureFlags( - // ignore: avoid_redundant_argument_values - isExplicitPackageDependenciesEnabled: false, - ); - } - setUp(() { Cache.disableLocking(); fileSystem = MemoryFileSystem.test(); @@ -292,53 +280,6 @@ void main() { FileSystem: () => fileSystem, }, ); - - testUsingContext( - 'pub get triggers localizations generation when generate: true', - () async { - final File pubspecFile = fileSystem.currentDirectory.childFile('pubspec.yaml')..createSync(); - pubspecFile.writeAsStringSync(''' -name: my_app -flutter: - generate: true -'''); - fileSystem.currentDirectory.childFile('l10n.yaml') - ..createSync() - ..writeAsStringSync(''' - arb-dir: lib/l10n - '''); - 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 PackagesGetCommand command = PackagesGetCommand('get', '', PubContext.pubGet); - final CommandRunner commandRunner = createTestCommandRunner(command); - - await commandRunner.run(['get']); - 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); - expect(outputDirectory.childFile('app_localizations.dart').existsSync(), true); - }, - overrides: { - Pub: () => pub, - ProcessManager: () => FakeProcessManager.any(), - FileSystem: () => fileSystem, - FeatureFlags: disableExplicitPackageDependencies, - }, - ); } class FakePub extends Fake implements Pub { @@ -353,7 +294,6 @@ class FakePub extends Fake implements Pub { required PubContext context, required String command, bool touchesPackageConfig = false, - bool generateSyntheticPackage = false, PubOutputMode outputMode = PubOutputMode.all, }) async { if (project != null) { 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 eada63e9e039c..2e50bba76d0c4 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -58,8 +58,11 @@ void main() { ); final Directory package = fs.directory('package'); - package.childFile('pubspec.yaml').createSync(recursive: true); - package.childFile('pubspec.yaml').writeAsStringSync(_pubspecContents); + + package.childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(_pubspecContents); + writePackageConfigFiles( directory: package, packages: { @@ -624,32 +627,12 @@ resolution: workspace // We expect [isolateSpawningTesterPackageConfigFile] to contain the // union of the packages in [_packageConfigContents] and // [_flutterToolsPackageConfigContents]. - expect( - isolateSpawningTesterPackageConfigFile.readAsStringSync().contains( - '"name": "integration_test"', - ), - true, - ); - expect( - isolateSpawningTesterPackageConfigFile.readAsStringSync().contains('"name": "ffi"'), - true, - ); - expect( - isolateSpawningTesterPackageConfigFile.readAsStringSync().contains('"name": "test"'), - true, - ); - expect( - isolateSpawningTesterPackageConfigFile.readAsStringSync().contains( - '"name": "test_api"', - ), - true, - ); - expect( - isolateSpawningTesterPackageConfigFile.readAsStringSync().contains( - '"name": "test_core"', - ), - true, - ); + final String configContents = isolateSpawningTesterPackageConfigFile.readAsStringSync(); + expect(configContents.contains('"name": "integration_test"'), true); + expect(configContents.contains('"name": "ffi"'), true); + expect(configContents.contains('"name": "test"'), true); + expect(configContents.contains('"name": "test_api"'), true); + expect(configContents.contains('"name": "test_core"'), true); }, ); expect(caughtToolExit, true); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart index 40849c1aa3d89..9331076bc865e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart @@ -10,13 +10,76 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/update_packages.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/project.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:test/fake.dart'; -import 'package:yaml/yaml.dart'; import '../../src/context.dart'; -import '../../src/package_config.dart'; import '../../src/test_flutter_command_runner.dart'; +// An example pubspec.yaml from flutter, not necessary for it to be up to date. +const String kFlutterWorkspacePubspecYaml = r''' +name: flutter +description: A framework for writing Flutter applications +homepage: http://flutter.dev + +environment: + sdk: ^3.7.0-0 + +workspace: + - packages/flutter + - examples + +dependencies: + # To update these, use "flutter update-packages --force-upgrade". + collection: 1.14.11 + meta: 1.1.8 + typed_data: ^1.1.6 + vector_math: 2.0.8 + test_api: 0.7.4 + + sky_engine: + sdk: flutter + + gallery: + git: + url: https://github.com/flutter/gallery.git + ref: d00362e6bdd0f9b30bba337c358b9e4a6e4ca950 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_goldens: + sdk: flutter + + archive: 3.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +# PUBSPEC CHECKSUM: u6pfsu +'''; + +const String kWidgetTestPubspecYaml = r''' +name: widget_preview_scaffold +description: Scaffolding for Flutter Widget Previews +publish_to: "none" +version: 0.0.1 + +environment: + sdk: ^3.8.0-265.0.dev + +dependencies: + flutter: + sdk: flutter + flutter_test: + sdk: flutter + # These will be replaced with proper constraints after the template is hydrated. + dtd: 2.5.1 + flutter_lints: 5.0.0 + stack_trace: 1.12.1 + url_launcher: 6.3.1 + +# PUBSPEC CHECKSUM: giib17 +'''; + // An example pubspec.yaml from flutter, not necessary for it to be up to date. const String kFlutterPubspecYaml = r''' name: flutter @@ -26,11 +89,13 @@ homepage: http://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: # To update these, use "flutter update-packages --force-upgrade". collection: 1.14.11 meta: 1.1.8 - typed_data: 1.1.6 + typed_data: ^1.1.6 vector_math: 2.0.8 sky_engine: @@ -47,9 +112,33 @@ dev_dependencies: flutter_goldens: sdk: flutter - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +# PUBSPEC CHECKSUM: dn2ahm +'''; + +// An example pubspec.yaml, not necessary for it to be up to date. +const String kFlutterToolsPubspecYaml = r''' +name: flutter_tools +description: Examples for flutter +homepage: http://flutter.dev + +version: 1.0.0 + +resolution: workspace + +environment: + sdk: '>=3.2.0-0 <4.0.0' + flutter: ">=2.5.0-6.0.pre.30 <3.0.0" + +dependencies: + test_api: 0.7.4 + flutter: + sdk: flutter + + archive: 3.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1234 +# PUBSPEC CHECKSUM: 2ut14g '''; // An example pubspec.yaml, not necessary for it to be up to date. @@ -60,6 +149,8 @@ homepage: http://flutter.dev version: 1.0.0 +resolution: workspace + environment: sdk: '>=3.2.0-0 <4.0.0' flutter: ">=2.5.0-6.0.pre.30 <3.0.0" @@ -69,9 +160,9 @@ dependencies: flutter: sdk: flutter - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + archive: 3.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6543 +# PUBSPEC CHECKSUM: ivm9uf '''; const String kVersionJson = ''' @@ -92,8 +183,7 @@ void main() { group('update-packages', () { late FileSystem fileSystem; late Directory flutterSdk; - late Directory flutter; - late FakePub pub; + late _FakePub pub; late FakeProcessManager processManager; late BufferLogger logger; @@ -109,32 +199,54 @@ void main() { flutterSdk.childDirectory('bin').childDirectory('cache').childFile('flutter.version.json') ..createSync(recursive: true) ..writeAsStringSync(kVersionJson); - flutter = flutterSdk.childDirectory('packages').childDirectory('flutter') - ..createSync(recursive: true); flutterSdk.childDirectory('dev').createSync(recursive: true); flutterSdk.childDirectory('examples').childFile('pubspec.yaml') ..createSync(recursive: true) ..writeAsStringSync(kExamplesPubspecYaml); - flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml); + flutterSdk.childDirectory('packages').childDirectory('flutter_test').childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(kFlutterToolsPubspecYaml); + flutterSdk + .childDirectory('packages') + .childDirectory('flutter_localizations') + .childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(kFlutterToolsPubspecYaml); + flutterSdk + .childDirectory('packages') + .childDirectory('flutter_tools') + .childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(kFlutterToolsPubspecYaml); + flutterSdk.childDirectory('packages').childDirectory('flutter').childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(kFlutterPubspecYaml); + flutterSdk.childFile('pubspec.yaml') + ..createSync() + ..writeAsStringSync(kFlutterWorkspacePubspecYaml); + flutterSdk + .childDirectory('packages') + .childDirectory('flutter_tools') + .childDirectory('test') + .childDirectory('widget_preview_scaffold.shard') + .childDirectory('widget_preview_scaffold') + .childFile('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(kWidgetTestPubspecYaml); Cache.flutterRoot = flutterSdk.absolute.path; - pub = FakePub(); + pub = _FakePub(); processManager = FakeProcessManager.empty(); }); testUsingContext( - 'updates packages', + 'updates packages - only runs pub get', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); await createTestCommandRunner(command).run(['update-packages']); expect( - pub.pubGetDirectories, - equals([ - '/.tmp_rand0/flutter_update_packages.rand0/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), + pub.pubspecs[flutterSdk.absolute.path]!.first.dependencies, + Pubspec.parse(kFlutterWorkspacePubspecYaml).dependencies, ); - expect(pub.pubBatchDirectories, isEmpty); }, overrides: { Pub: () => pub, @@ -145,21 +257,16 @@ void main() { ); testUsingContext( - 'force updates packages', + '--force-upgrade updates packages', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); await createTestCommandRunner(command).run(['update-packages', '--force-upgrade']); expect( - pub.pubGetDirectories, - equals([ - '/.tmp_rand0/flutter_update_packages.rand0/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), - ); - expect( - pub.pubBatchDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), + pub.pubspecs[flutterSdk.absolute.path]!.first.dependencies, + (Pubspec.parse(kFlutterWorkspacePubspecYaml) + ..dependencies['typed_data'] = HostedDependency( + version: VersionConstraint.parse('^1.1.1'), + )).dependencies, ); }, overrides: { @@ -171,23 +278,18 @@ void main() { ); testUsingContext( - 'force updates packages --jobs=1', + '--cherry-pick-package', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); await createTestCommandRunner( command, - ).run(['update-packages', '--force-upgrade', '--jobs=1']); - expect( - pub.pubGetDirectories, - equals([ - '/.tmp_rand0/flutter_update_packages.rand0/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), - ); + ).run(['update-packages', '--cherry-pick=vector_math:2.0.9']); expect( - pub.pubBatchDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), + pub.pubspecs[flutterSdk.absolute.path]!.first.dependencies, + (Pubspec.parse(kFlutterWorkspacePubspecYaml) + ..dependencies['vector_math'] = HostedDependency( + version: VersionConstraint.parse('2.0.9'), + )).dependencies, ); }, overrides: { @@ -195,27 +297,24 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => processManager, Cache: () => Cache.test(processManager: processManager), + Logger: () => logger, }, ); testUsingContext( - '--transitive-closure --consumer-only', + '--cherry-pick-package with caret', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); await createTestCommandRunner( command, - ).run(['update-packages', '--transitive-closure', '--consumer-only']); + ).run(['update-packages', '--cherry-pick=vector_math:^2.0.9']); expect( - pub.pubGetDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), + pub.pubspecs[flutterSdk.absolute.path]!.first.dependencies, + (Pubspec.parse(kFlutterWorkspacePubspecYaml) + ..dependencies['vector_math'] = HostedDependency( + version: VersionConstraint.parse('^2.0.9'), + )).dependencies, ); - expect( - pub.pubBatchDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), - ); - // Expecting a line like: - // 'flutter -> {collection, meta, typed_data, vector_math}' - expect(logger.statusText, contains(RegExp(r'flutter -> {([a-z_]+, )*([a-z_]+)+}'))); }, overrides: { Pub: () => pub, @@ -227,36 +326,23 @@ void main() { ); testUsingContext( - '--cherry-pick-package', + '--cherry-pick-package muliple', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); - await createTestCommandRunner(command).run([ - 'update-packages', - '--cherry-pick-package=vector_math', - '--cherry-pick-version=2.0.9', - ]); - expect( - pub.pubGetDirectories, - equals([ - '/.tmp_rand0/flutter_update_packages.rand0/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), - ); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); + await createTestCommandRunner( + command, + ).run(['update-packages', '--cherry-pick=vector_math:^2.0.9,meta:1.0.5']); expect( - pub.pubBatchDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), + pub.pubspecs[flutterSdk.absolute.path]!.first.dependencies, + (Pubspec.parse(kFlutterWorkspacePubspecYaml) + ..dependencies['vector_math'] = HostedDependency( + version: VersionConstraint.parse('^2.0.9'), + ) + ..dependencies['meta'] = HostedDependency( + version: VersionConstraint.parse('1.0.5'), + )) + .dependencies, ); - expect(pub.pubspecYamls, hasLength(3)); - final String output = pub.pubspecYamls.first; - expect(output, isNotNull); - expect(output, contains('collection: 1.14.11\n')); - expect(output, contains('meta: 1.1.8\n')); - expect(output, contains('typed_data: 1.1.6\n')); - expect(output, contains('vector_math: 2.0.9\n')); - expect(output, isNot(contains('vector_math: 2.0.8'))); - expect(output, isNot(contains('vector_math: ">= 2.0.8"'))); - expect(output, isNot(contains("vector_math: '>= 2.0.8'"))); }, overrides: { Pub: () => pub, @@ -270,28 +356,8 @@ void main() { testUsingContext( '--force-upgrade', () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); + final UpdatePackagesCommand command = UpdatePackagesCommand(verboseHelp: false); await createTestCommandRunner(command).run(['update-packages', '--force-upgrade']); - expect( - pub.pubGetDirectories, - equals([ - '/.tmp_rand0/flutter_update_packages.rand0/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), - ); - expect( - pub.pubBatchDirectories, - equals(['/.tmp_rand0/flutter_update_packages.rand0/synthetic_package']), - ); - expect(pub.pubspecYamls, hasLength(3)); - final String output = pub.pubspecYamls.first; - expect(output, isNotNull); - expect(output, contains("collection: '>= 1.14.11'\n")); - expect(output, contains("meta: '>= 1.1.8'\n")); - expect(output, contains("typed_data: '>= 1.1.6'\n")); - expect(output, contains("vector_math: '>= 2.0.8'\n")); - expect(output, isNot(contains('vector_math: 2.0.8'))); }, overrides: { Pub: () => pub, @@ -301,78 +367,37 @@ void main() { Logger: () => logger, }, ); - - testUsingContext( - 'force updates packages --synthetic-package-path', - () async { - final UpdatePackagesCommand command = UpdatePackagesCommand(); - const String dir = '/path/to/synthetic/package'; - await createTestCommandRunner( - command, - ).run(['update-packages', '--force-upgrade', '--synthetic-package-path=$dir']); - expect( - pub.pubGetDirectories, - equals([ - '$dir/synthetic_package', - '/flutter/examples', - '/flutter/packages/flutter', - ]), - ); - expect(pub.pubBatchDirectories, equals(['$dir/synthetic_package'])); - }, - overrides: { - Pub: () => pub, - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Cache: () => Cache.test(processManager: processManager), - }, - ); }); +} - group('generateFakePubspec', () { - const String prevVersion = '1.2.0'; - testUsingContext('constrains package versions to >= previous version if doUpgrade: true', () { - final String pubspecSource = generateFakePubspec([ - PubspecDependency( - ' foo: $prevVersion', - 'foo', - '', - version: prevVersion, - sourcePath: '/path/to/pubspec.yaml', - kind: DependencyKind.normal, - isTransitive: false, - isDevDependency: false, - ), - ], doUpgrade: true); - final YamlMap pubspec = loadYaml(pubspecSource) as YamlMap; - expect((pubspec['dependencies'] as YamlMap)['foo'], '>= $prevVersion'); - }); +class _FakePub extends Fake implements Pub { + _FakePub(); - testUsingContext('uses previous package versions doUpgrade: false', () { - final String pubspecSource = generateFakePubspec([ - PubspecDependency( - ' foo: $prevVersion', - 'foo', - '', - version: prevVersion, - sourcePath: '/path/to/pubspec.yaml', - kind: DependencyKind.normal, - isTransitive: false, - isDevDependency: false, - ), - ]); - final YamlMap pubspec = loadYaml(pubspecSource) as YamlMap; - expect((pubspec['dependencies'] as YamlMap)['foo'], prevVersion); - }); - }); -} + Map> pubspecs = >{}; -class FakePub extends Fake implements Pub { - FakePub(); + @override + Future interactively( + List arguments, { + FlutterProject? project, + required PubContext context, + required String command, + bool touchesPackageConfig = false, + PubOutputMode outputMode = PubOutputMode.all, + }) async { + if (project == null) { + throw ArgumentError('project must not be null'); + } - final List pubGetDirectories = []; - final List pubBatchDirectories = []; - final List pubspecYamls = []; + Pubspec pubspec; + if (command == 'add') { + pubspec = _add(arguments, project: project); + } else if (command == 'update') { + pubspec = _upgrade(arguments, project: project); + } else { + throw ArgumentError('Unknown command'); + } + (pubspecs[project.directory.path] ??= []).add(pubspec); + } @override Future get({ @@ -380,63 +405,33 @@ class FakePub extends Fake implements Pub { required FlutterProject project, bool upgrade = false, bool offline = false, - bool generateSyntheticPackage = false, - bool generateSyntheticPackageForExample = false, String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async { - pubGetDirectories.add(project.directory.path); - pubspecYamls.add(project.directory.childFile('pubspec.yaml').readAsStringSync()); - project.directory.childFile('pubspec.lock') - ..createSync(recursive: true) - ..writeAsStringSync(''' -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: "direct dev" - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" -sdks: - dart: ">=2.14.0 <3.0.0" -'''); - writePackageConfigFiles(directory: project.directory, mainLibName: 'my_app'); + (pubspecs[project.directory.path] ??= []).add( + Pubspec.parse(project.pubspecFile.readAsStringSync()), + ); } - @override - Future batch( - List arguments, { - required PubContext context, - String? directory, - MessageFilter? filter, - String failureMessage = 'pub failed', - }) async { - if (directory != null) { - pubBatchDirectories.add(directory); - } - - ''' -Dart SDK 2.16.0-144.0.dev -Flutter SDK 2.9.0-1.0.pre.263 -flutter_api_samples 1.0.0 + Pubspec _add(List arguments, {required FlutterProject project}) { + final List split = arguments.first.split(':'); + final String packageName = split[0]; + final String packageVersion = split[1]; + final Pubspec pubspec = Pubspec.parse(project.pubspecFile.readAsStringSync()); + pubspec.dependencies[packageName] = HostedDependency( + version: VersionConstraint.parse(packageVersion), + ); + return pubspec; + } -dependencies: -- cupertino_icons 1.0.4 -- collection 1.15.0 -- meta 1.7.0 -- typed_data 1.3.0 [collection] -- vector_math 2.1.1 - -dev dependencies: - -transitive dependencies: -- platform 3.1.0 -- process 4.2.4 [file path platform] -'''.split('\n').forEach(filter!); + Pubspec _upgrade(List arguments, {required FlutterProject project}) { + final String pubspec = project.pubspecFile.readAsStringSync(); + project.pubspecFile.writeAsStringSync( + pubspec.replaceFirst('typed_data: ^1.1.6', 'typed_data: ^1.1.1'), + ); + return Pubspec.parse(project.pubspecFile.readAsStringSync()); } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart index 9dd1f8812e308..aab53c6e25fda 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_code_generator_test.dart @@ -45,6 +45,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter/widget_previews.dart'; import 'brightness.dart'; +import 'localizations.dart'; import 'theme.dart'; import 'wrapper.dart'; @@ -61,6 +62,7 @@ Widget barPreview2() => Text('Foo'); wrapper: wrapper, brightness: Brightness.dark, theme: myThemeData, + localizations: myLocalizations, ) WidgetBuilder barPreview3() => (BuildContext context) { return Text('Foo'); @@ -87,6 +89,27 @@ Widget wrapper(Widget widget) { } '''; +const String kLocalizationsDart = ''' +import 'package:flutter/widget_previews.dart'; + +PreviewLocalizationsData myLocalizations() { + return PreviewLocalizationsData( + locale: Locale('en'), + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: [ + Locale('en'), // English + Locale('es'), // Spanish + ], + localeListResolutionCallback: (List? locales, Iterable supportedLocales) => null, + localeResolutionCallback: (Locale? locale, Iterable supportedLocales) => null, + ); +} +'''; + // Note: this test isn't under the general.shard since tests under that directory // have a 2000ms time out and these tests write to the real file system and watch // directories for changes. This can be slow on heavily loaded machines and cause @@ -113,6 +136,7 @@ void main() { ..childFile('lib/foo.dart').writeAsStringSync(kFooDart) ..childFile('lib/src/bar.dart').writeAsStringSync(kBarDart) ..childFile('lib/src/brightness.dart').writeAsStringSync(kBrightnessDart) + ..childFile('lib/src/localizations.dart').writeAsStringSync(kLocalizationsDart) ..childFile('lib/src/wrapper.dart').writeAsStringSync(kWrapperDart) ..childFile('lib/src/theme.dart').writeAsStringSync(kThemeDart); project = FlutterProject.fromDirectoryTest(projectDir); @@ -172,8 +196,9 @@ import 'package:foo_project/src/bar.dart' as _i3; import 'package:foo_project/src/brightness.dart' as _i4; import 'dart:ui' as _i5; import 'package:foo_project/src/theme.dart' as _i6; -import 'package:foo_project/src/wrapper.dart' as _i7; -import 'package:flutter/widgets.dart' as _i8; +import 'package:foo_project/src/localizations.dart' as _i7; +import 'package:foo_project/src/wrapper.dart' as _i8; +import 'package:flutter/widgets.dart' as _i9; List<_i1.WidgetPreview> previews() => [ _i1.WidgetPreview(builder: () => _i2.preview()), @@ -191,7 +216,8 @@ List<_i1.WidgetPreview> previews() => [ textScaleFactor: 50, theme: _i6.myThemeData(), brightness: _i5.Brightness.dark, - builder: () => _i7.wrapper(_i8.Builder(builder: _i3.barPreview3())), + localizations: _i7.myLocalizations(), + builder: () => _i8.wrapper(_i9.Builder(builder: _i3.barPreview3())), ), ]; '''; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_test.dart index 0306771a9cc4b..5b764fb6a2bf1 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/preview_detector_test.dart @@ -116,6 +116,7 @@ void main() { wrapper: 'testWrapper', theme: 'theming', brightness: 'Brightness.dark', + localizations: 'localizations', ), PreviewDetailsMatcher( functionName: 'MyWidget.preview', @@ -198,6 +199,7 @@ void main() { wrapper: 'testWrapper', theme: 'theming', brightness: 'Brightness.dark', + localizations: 'localizations', ), PreviewDetailsMatcher( functionName: 'MyWidget.preview', @@ -273,6 +275,7 @@ class PreviewDetailsMatcher extends Matcher { this.wrapper, this.theme, this.brightness, + this.localizations, }) { if (name != null && nameSymbol != null) { fail('name and nameSymbol cannot both be provided.'); @@ -292,6 +295,7 @@ class PreviewDetailsMatcher extends Matcher { final String? wrapper; final String? theme; final String? brightness; + final String? localizations; @override Description describe(Description description) { @@ -358,6 +362,11 @@ class PreviewDetailsMatcher extends Matcher { actual: item.brightness, expected: brightness, ); + checkPropertyMatch( + name: PreviewDetails.kLocalizations, + actual: item.localizations, + expected: localizations, + ); return matches; } } @@ -384,8 +393,34 @@ PreviewThemeData theming() => PreviewThemeData( cupertinoDark: CupertinoThemeData(primaryColor: Colors.purple), ); +PreviewLocalizationsData localizations() { + return PreviewLocalizationsData( + locale: Locale('en'), + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: [ + Locale('en'), // English + Locale('es'), // Spanish + ], + localeListResolutionCallback: + (List? locales, Iterable supportedLocales) => null, + localeResolutionCallback: (Locale? locale, Iterable supportedLocales) => null, + ); +} + const String kAttributesPreview = 'Attributes preview'; -@Preview(name: kAttributesPreview, size: Size(100.0, 100), textScaleFactor: 2.0, wrapper: testWrapper, theme: theming, brightness: Brightness.dark) +@Preview( + name: kAttributesPreview, + size: Size(100.0, 100), + textScaleFactor: 2.0, + wrapper: testWrapper, + theme: theming, + brightness: Brightness.dark, + localizations: localizations, +) Widget attributesPreview() { return Text('Attributes'); } 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 f17fa5ec3a080..568e86f6c0b84 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 @@ -249,7 +249,7 @@ void main() { '--no-debug', '--no-profile', '--target-platform', - 'android-x86', + 'android-x64', '--tree-shake-icons', '--flavor', 'free', @@ -272,7 +272,7 @@ void main() { final AndroidBuildInfo androidBuildInfo = (buildAarCall.namedArguments[#androidBuildInfo] as Set).single; - expect(androidBuildInfo.targetArchs, [AndroidArch.x86]); + expect(androidBuildInfo.targetArchs, [AndroidArch.x86_64]); final BuildInfo buildInfo = androidBuildInfo.buildInfo; expect(buildInfo.mode, BuildMode.release); @@ -577,10 +577,10 @@ class FakePub extends Fake implements Pub { required FlutterProject project, bool upgrade = false, bool offline = false, - bool generateSyntheticPackage = false, String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async {} } 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 6766840eef4ee..5238157861e07 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 @@ -78,7 +78,7 @@ void main() { Event.commandUsageValues( workflow: 'apk', commandHasTerminal: false, - buildApkTargetPlatform: 'android-arm,android-arm64,android-x86,android-x64', + buildApkTargetPlatform: 'android-arm,android-arm64,android-x64', buildApkBuildMode: 'debug', buildApkSplitPerAbi: false, ), @@ -92,7 +92,7 @@ void main() { Event.commandUsageValues( workflow: 'apk', commandHasTerminal: false, - buildApkTargetPlatform: 'android-arm,android-arm64,android-x86,android-x64', + buildApkTargetPlatform: 'android-arm,android-arm64,android-x64', buildApkBuildMode: 'jit_release', buildApkSplitPerAbi: false, ), 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 db5f74366b53c..2e55c3d1f8df8 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -80,10 +80,7 @@ const String samplesIndexJson = ''' ]'''; /// These files are generated for all project types. -const List flutterPluginsIgnores = [ - '.flutter-plugins', - '.flutter-plugins-dependencies', -]; +const List flutterPluginsIgnores = ['.flutter-plugins-dependencies']; void main() { late Directory tempDir; 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 6f1048ef57b42..7545fec737cdd 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -15,7 +15,6 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/packages.dart'; import 'package:flutter_tools/src/dart/pub.dart'; -import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:unified_analytics/unified_analytics.dart'; import 'package:yaml/yaml.dart'; @@ -30,15 +29,6 @@ import '../../src/test_flutter_command_runner.dart'; void main() { late FakeStdio mockStdio; - // TODO(matanlurey): Remove after `flutter_gen` is removed. - // See https://github.com/flutter/flutter/issues/102983 for details. - FeatureFlags disableExplicitPackageDependencies() { - return TestFeatureFlags( - // ignore: avoid_redundant_argument_values - isExplicitPackageDependenciesEnabled: false, - ); - } - setUp(() { mockStdio = FakeStdio()..stdout.terminalColumns = 80; @@ -320,48 +310,6 @@ void main() { }, ); - testUsingContext( - 'get generates synthetic package when l10n.yaml has synthetic-package: true', - () async { - final String projectPath = await createProject( - tempDir, - arguments: ['--no-pub', '--template=module'], - ); - final Directory projectDir = globals.fs.directory(projectPath); - projectDir.childDirectory('lib').childDirectory('l10n').childFile('app_en.arb') - ..createSync(recursive: true) - ..writeAsStringSync('{ "hello": "Hello world!" }'); - String pubspecFileContent = projectDir.childFile('pubspec.yaml').readAsStringSync(); - pubspecFileContent = pubspecFileContent.replaceFirst(RegExp(r'\nflutter\:'), ''' -flutter: - generate: true -'''); - projectDir.childFile('pubspec.yaml').writeAsStringSync(pubspecFileContent); - projectDir.childFile('l10n.yaml').writeAsStringSync('synthetic-package: true'); - await runCommandIn(projectPath, 'get'); - expect( - projectDir - .childDirectory('.dart_tool') - .childDirectory('flutter_gen') - .childDirectory('gen_l10n') - .childFile('app_localizations.dart') - .existsSync(), - true, - ); - }, - overrides: { - Pub: - () => Pub( - fileSystem: globals.fs, - logger: globals.logger, - processManager: globals.processManager, - botDetector: globals.botDetector, - platform: globals.platform, - ), - FeatureFlags: disableExplicitPackageDependencies, - }, - ); - testUsingContext( 'get fetches packages for a workspace', () async { @@ -439,7 +387,7 @@ workspace: ); testUsingContext( - 'get generates normal files when l10n.yaml has synthetic-package: false', + 'get generates files into lib/l10n', () async { final String projectPath = await createProject( tempDir, @@ -455,7 +403,7 @@ flutter: generate: true '''); projectDir.childFile('pubspec.yaml').writeAsStringSync(pubspecFileContent); - projectDir.childFile('l10n.yaml').writeAsStringSync('synthetic-package: false'); + projectDir.childFile('l10n.yaml').createSync(); await runCommandIn(projectPath, 'get'); expect( projectDir diff --git a/packages/flutter_tools/test/commands.shard/permeable/utils/project_testing_utils.dart b/packages/flutter_tools/test/commands.shard/permeable/utils/project_testing_utils.dart index d7f41740b2132..4b22016b3b75e 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/utils/project_testing_utils.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/utils/project_testing_utils.dart @@ -38,6 +38,28 @@ class LoggingProcessManager extends LocalProcessManager { ); } + @override + Future run( + List command, { + String? workingDirectory, + Map? environment, + bool includeParentEnvironment = true, + bool runInShell = false, + Encoding? stdoutEncoding = systemEncoding, + Encoding? stderrEncoding = systemEncoding, + }) { + commands.add(command.map((Object arg) => arg.toString()).toList()); + return super.run( + command, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + runInShell: runInShell, + stdoutEncoding: stdoutEncoding, + stderrEncoding: stderrEncoding, + ); + } + void clear() { commands.clear(); } diff --git a/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart b/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart index cc5013514f19b..df33b7ef32cd5 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/widget_preview_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:io' as io show IOOverrides; - import 'package:args/command_runner.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; @@ -18,6 +16,7 @@ import 'package:flutter_tools/src/base/signals.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/widget_preview.dart'; import 'package:flutter_tools/src/dart/pub.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/widget_preview/preview_code_generator.dart'; @@ -28,6 +27,7 @@ import '../../src/test_flutter_command_runner.dart'; import 'utils/project_testing_utils.dart'; void main() { + late Directory originalCwd; late Directory tempDir; late LoggingProcessManager loggingProcessManager; late FakeStdio mockStdio; @@ -37,6 +37,7 @@ void main() { late Platform platform; setUp(() async { + originalCwd = globals.fs.currentDirectory; await ensureFlutterToolsSnapshot(); loggingProcessManager = LoggingProcessManager(); logger = BufferLogger.test(); @@ -55,6 +56,7 @@ void main() { tearDown(() { tryToDelete(tempDir); fs.dispose(); + globals.fs.currentDirectory = originalCwd; }); Future createRootProject() async { @@ -92,14 +94,17 @@ void main() { required Directory? rootProject, List? arguments, }) async { + // This might get changed during the test, so keep track of the original directory. + final Directory current = fs.currentDirectory; await runWidgetPreviewCommand([ 'start', ...?arguments, '--no-launch-previewer', + '--verbose', if (rootProject != null) rootProject.path, ]); final Directory widgetPreviewScaffoldDir = widgetPreviewScaffoldFromRootProject( - rootProject: rootProject ?? fs.currentDirectory, + rootProject: rootProject ?? current, ); // Don't perform analysis on Windows since `dart pub add` will use '\' for // path dependencies and cause analysis to fail. @@ -108,6 +113,7 @@ void main() { if (!platform.isWindows) { await analyzeProject(widgetPreviewScaffoldDir.path); } + fs.currentDirectory = current; } Future cleanWidgetPreview({required Directory rootProject}) async { @@ -158,6 +164,8 @@ void main() { await startWidgetPreview(rootProject: rootProject); }, overrides: { + FileSystem: () => fs, + ProcessManager: () => loggingProcessManager, Pub: () => Pub.test( fileSystem: fs, @@ -174,12 +182,13 @@ void main() { 'start creates .dart_tool/widget_preview_scaffold in the CWD', () async { final Directory rootProject = await createRootProject(); - await io.IOOverrides.runZoned>(() async { - // Try to execute using the CWD. - await startWidgetPreview(rootProject: null); - }, getCurrentDirectory: () => rootProject); + // Try to execute using the CWD. + fs.currentDirectory = rootProject; + await startWidgetPreview(rootProject: null); }, overrides: { + FileSystem: () => fs, + ProcessManager: () => loggingProcessManager, Pub: () => Pub.test( fileSystem: fs, @@ -257,13 +266,16 @@ List<_i1.WidgetPreview> previews() => [ PreviewCodeGenerator.generatedPreviewFilePath, ); - await io.IOOverrides.runZoned>(() async { - // Try to execute using the CWD. - await startWidgetPreview(rootProject: null); - expect(generatedFile.readAsStringSync(), expectedGeneratedFileContents); - }, getCurrentDirectory: () => fs.directory(rootProject)); + // Try to execute using the CWD. + + fs.currentDirectory = rootProject; + await startWidgetPreview(rootProject: null); + + expect(generatedFile.readAsStringSync(), expectedGeneratedFileContents); }, overrides: { + FileSystem: () => fs, + ProcessManager: () => loggingProcessManager, Pub: () => Pub.test( fileSystem: fs, diff --git a/packages/flutter_tools/test/data/vscode/application/resources/app/package.json b/packages/flutter_tools/test/data/vscode/application/resources/app/package.json new file mode 100644 index 0000000000000..e4e72b6e0ba41 --- /dev/null +++ b/packages/flutter_tools/test/data/vscode/application/resources/app/package.json @@ -0,0 +1,4 @@ +{ + "name": "fake-vs-code-install-for-tests", + "version": "1.2.3" +} diff --git a/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart b/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart index 507f2dec96e03..104f04f7dd5aa 100644 --- a/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_device_start_test.dart @@ -128,46 +128,6 @@ void main() { }); } - testWithoutContext('AndroidDevice.startApp does not allow release builds on x86', () async { - final AndroidDevice device = AndroidDevice( - '1234', - modelID: 'TestModel', - fileSystem: fileSystem, - processManager: processManager, - logger: BufferLogger.test(), - platform: FakePlatform(), - androidSdk: androidSdk, - ); - final File apkFile = fileSystem.file('app-debug.apk')..createSync(); - final AndroidApk apk = AndroidApk( - id: 'FlutterApp', - applicationPackage: apkFile, - launchActivity: 'FlutterActivity', - versionCode: 1, - ); - - processManager.addCommand(kAdbVersionCommand); - processManager.addCommand(kStartServer); - - // This configures the target platform of the device. - processManager.addCommand( - const FakeCommand( - command: ['adb', '-s', '1234', 'shell', 'getprop'], - stdout: '[ro.product.cpu.abi]: [x86]', - ), - ); - - final LaunchResult launchResult = await device.startApp( - apk, - prebuiltApplication: true, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), - platformArgs: {}, - ); - - expect(launchResult.started, false); - expect(processManager, hasNoRemainingExpectations); - }); - testWithoutContext('AndroidDevice.startApp forwards all supported debugging options', () async { final AndroidDevice device = AndroidDevice( '1234', diff --git a/packages/flutter_tools/test/general.shard/android/android_device_test.dart b/packages/flutter_tools/test/general.shard/android/android_device_test.dart index 3a2da8053af30..a9bc4c3cb2834 100644 --- a/packages/flutter_tools/test/general.shard/android/android_device_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_device_test.dart @@ -78,7 +78,6 @@ void main() { // The format is [ABI, ABI list]: expected target platform. final Map, TargetPlatform> values = , TargetPlatform>{ ['x86_64', 'unknown']: TargetPlatform.android_x64, - ['x86', 'unknown']: TargetPlatform.android_x86, // The default ABI is arm32 ['???', 'unknown']: TargetPlatform.android_arm, ['arm64-v8a', 'arm64-v8a,']: TargetPlatform.android_arm64, @@ -107,7 +106,6 @@ void main() { // The format is [ABI, ABI list]: expected release mode support. final Map, bool> values = , bool>{ ['x86_64', 'unknown']: true, - ['x86', 'unknown']: false, // The default ABI is arm32 ['???', 'unknown']: true, ['arm64-v8a', 'arm64-v8a,']: true, diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index 0b272f802e003..2d560f3444abc 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -865,6 +865,16 @@ void main() { /BUNDLE-METADATA/com.android.tools.build.debugsymbols/ /BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/ /BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libflutter.so.sym +'''; + + // Output from `/tools/bin/apkanalyzer files list ` + // on an aab containing the debug info and symbol tables. + const String apkanalyzerOutputWithDebugInfoAndSymFiles = + apkanalyzerOutputWithoutSymFiles + + r''' +/BUNDLE-METADATA/com.android.tools.build.debugsymbols/ +/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/ +/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libflutter.so.dbg '''; void createSharedGradleFiles() { @@ -956,6 +966,71 @@ void main() { overrides: {AndroidStudio: () => FakeAndroidStudio()}, ); + testUsingContext( + 'build succeeds when debug info and symbol tables present for at least one architecture', + () async { + final AndroidGradleBuilder builder = AndroidGradleBuilder( + java: FakeJava(), + logger: logger, + processManager: processManager, + fileSystem: fileSystem, + artifacts: Artifacts.test(), + analytics: fakeAnalytics, + gradleUtils: FakeGradleUtils(), + platform: FakePlatform(environment: {'HOME': '/home'}), + androidStudio: FakeAndroidStudio(), + ); + processManager.addCommand( + FakeCommand(command: List.of(commonCommandPortion)..add('bundleRelease')), + ); + + createSharedGradleFiles(); + final File aabFile = createAabFile(BuildMode.release); + final AndroidSdk sdk = AndroidSdk.locateAndroidSdk()!; + + processManager.addCommand( + FakeCommand( + command: [ + sdk.getCmdlineToolsPath(apkAnalyzerBinaryName)!, + 'files', + 'list', + aabFile.path, + ], + stdout: apkanalyzerOutputWithDebugInfoAndSymFiles, + ), + ); + + final FlutterProject project = FlutterProject.fromDirectoryTest( + fileSystem.currentDirectory, + ); + project.android.appManifestFile + ..createSync(recursive: true) + ..writeAsStringSync(minimalV2EmbeddingManifest); + + await builder.buildGradleApp( + project: project, + androidBuildInfo: const AndroidBuildInfo( + BuildInfo( + BuildMode.release, + null, + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + ), + targetArchs: [ + AndroidArch.arm64_v8a, + AndroidArch.armeabi_v7a, + AndroidArch.x86_64, + ], + ), + target: 'lib/main.dart', + isBuildingBundle: true, + configOnly: false, + localGradleErrors: [], + ); + }, + overrides: {AndroidStudio: () => FakeAndroidStudio()}, + ); + testUsingContext( 'building a debug aab does not invoke apkanalyzer', () async { @@ -1225,86 +1300,6 @@ void main() { overrides: {AndroidStudio: () => FakeAndroidStudio()}, ); - testUsingContext( - 'prints deprecation warning when building for x86', - () async { - // See https://github.com/flutter/flutter/issues/157543 for details. - final AndroidGradleBuilder builder = AndroidGradleBuilder( - java: FakeJava(), - logger: logger, - processManager: processManager, - fileSystem: fileSystem, - artifacts: Artifacts.test(), - analytics: fakeAnalytics, - gradleUtils: FakeGradleUtils(), - platform: FakePlatform(), - androidStudio: FakeAndroidStudio(), - ); - processManager.addCommand( - const FakeCommand( - command: [ - 'gradlew', - '-q', - '-Ptarget-platform=android-x86', - '-Ptarget=lib/main.dart', - '-Pbase-application-name=android.app.Application', - '-Pdart-obfuscation=false', - '-Ptrack-widget-creation=false', - '-Ptree-shake-icons=false', - 'assembleRelease', - ], - ), - ); - fileSystem.directory('android').childFile('build.gradle').createSync(recursive: true); - - fileSystem.directory('android').childFile('gradle.properties').createSync(recursive: true); - - fileSystem.directory('android').childDirectory('app').childFile('build.gradle') - ..createSync(recursive: true) - ..writeAsStringSync('apply from: irrelevant/flutter.gradle'); - - fileSystem - .directory('build') - .childDirectory('app') - .childDirectory('outputs') - .childDirectory('flutter-apk') - .childFile('app-release.apk') - .createSync(recursive: true); - - final FlutterProject project = FlutterProject.fromDirectoryTest( - fileSystem.currentDirectory, - ); - project.android.appManifestFile - ..createSync(recursive: true) - ..writeAsStringSync(minimalV2EmbeddingManifest); - - await builder.buildGradleApp( - project: project, - androidBuildInfo: const AndroidBuildInfo( - BuildInfo( - BuildMode.release, - null, - treeShakeIcons: false, - packageConfigPath: '.dart_tool/package_config.json', - ), - targetArchs: [AndroidArch.x86], - ), - target: 'lib/main.dart', - isBuildingBundle: false, - configOnly: false, - localGradleErrors: const [], - ); - - expect( - logger.statusText, - contains('Built build/app/outputs/flutter-apk/app-release.apk (0.0MB)'), - ); - expect(logger.warningText, contains(androidX86DeprecationWarning)); - expect(processManager, hasNoRemainingExpectations); - }, - overrides: {AndroidStudio: () => FakeAndroidStudio()}, - ); - testUsingContext('Uses namespace attribute if manifest lacks a package attribute', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final AndroidSdk sdk = FakeAndroidSdk(); @@ -2052,7 +2047,7 @@ Gradle Crashed ); testUsingContext( - 'build apk uses selected local engine with x86 ABI', + 'build apk uses selected local engine with x64 ABI', () async { final AndroidGradleBuilder builder = AndroidGradleBuilder( java: FakeJava(), @@ -2060,7 +2055,7 @@ Gradle Crashed processManager: processManager, fileSystem: fileSystem, artifacts: Artifacts.testLocalEngine( - localEngine: 'out/android_x86', + localEngine: 'out/android_x64', localEngineHost: 'out/host_release', ), analytics: fakeAnalytics, @@ -2075,9 +2070,9 @@ Gradle Crashed '-q', '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', - '-Plocal-engine-out=out/android_x86', + '-Plocal-engine-out=out/android_x64', '-Plocal-engine-host-out=out/host_release', - '-Ptarget-platform=android-x86', + '-Ptarget-platform=android-x64', '-Ptarget=lib/main.dart', '-Pbase-application-name=android.app.Application', '-Pdart-obfuscation=false', @@ -2085,10 +2080,11 @@ Gradle Crashed '-Ptree-shake-icons=false', 'assembleRelease', ], + exitCode: 1, ), ); - fileSystem.file('out/android_x86/flutter_embedding_release.pom') + fileSystem.file('out/android_x64/flutter_embedding_release.pom') ..createSync(recursive: true) ..writeAsStringSync(''' @@ -2098,19 +2094,19 @@ Gradle Crashed '''); - fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true); - fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true); + fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true); + fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true); fileSystem - .file('out/android_x86/x86_release.maven-metadata.xml') + .file('out/android_x64/x86_64_release.maven-metadata.xml') .createSync(recursive: true); fileSystem - .file('out/android_x86/flutter_embedding_release.jar') + .file('out/android_x64/flutter_embedding_release.jar') .createSync(recursive: true); fileSystem - .file('out/android_x86/flutter_embedding_release.pom') + .file('out/android_x64/flutter_embedding_release.pom') .createSync(recursive: true); fileSystem - .file('out/android_x86/flutter_embedding_release.maven-metadata.xml') + .file('out/android_x64/flutter_embedding_release.maven-metadata.xml') .createSync(recursive: true); fileSystem.file('android/gradlew').createSync(recursive: true); @@ -2149,17 +2145,14 @@ Gradle Crashed ); testUsingContext( - 'build apk uses selected local engine with x64 ABI', + 'honors --no-android-gradle-daemon setting', () async { final AndroidGradleBuilder builder = AndroidGradleBuilder( java: FakeJava(), logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.testLocalEngine( - localEngine: 'out/android_x64', - localEngineHost: 'out/host_release', - ), + artifacts: Artifacts.test(), analytics: fakeAnalytics, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -2170,11 +2163,8 @@ Gradle Crashed command: [ 'gradlew', '-q', - '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', - '-Plocal-engine-build-mode=release', - '-Plocal-engine-out=out/android_x64', - '-Plocal-engine-host-out=out/host_release', - '-Ptarget-platform=android-x64', + '--no-daemon', + '-Ptarget-platform=android-arm,android-arm64,android-x64', '-Ptarget=lib/main.dart', '-Pbase-application-name=android.app.Application', '-Pdart-obfuscation=false', @@ -2182,36 +2172,10 @@ Gradle Crashed '-Ptree-shake-icons=false', 'assembleRelease', ], - exitCode: 1, ), ); - - fileSystem.file('out/android_x64/flutter_embedding_release.pom') - ..createSync(recursive: true) - ..writeAsStringSync(''' - - - 1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b - - - -'''); - fileSystem.file('out/android_x64/x86_64_release.pom').createSync(recursive: true); - fileSystem.file('out/android_x64/x86_64_release.jar').createSync(recursive: true); - fileSystem - .file('out/android_x64/x86_64_release.maven-metadata.xml') - .createSync(recursive: true); - fileSystem - .file('out/android_x64/flutter_embedding_release.jar') - .createSync(recursive: true); - fileSystem - .file('out/android_x64/flutter_embedding_release.pom') - .createSync(recursive: true); - fileSystem - .file('out/android_x64/flutter_embedding_release.maven-metadata.xml') - .createSync(recursive: true); - fileSystem.file('android/gradlew').createSync(recursive: true); + fileSystem.directory('android').childFile('gradle.properties').createSync(recursive: true); fileSystem.file('android/build.gradle').createSync(recursive: true); fileSystem.directory('android').childDirectory('app').childFile('build.gradle') @@ -2232,6 +2196,7 @@ Gradle Crashed BuildMode.release, null, treeShakeIcons: false, + androidGradleDaemon: false, packageConfigPath: '.dart_tool/package_config.json', ), ), @@ -2247,7 +2212,7 @@ Gradle Crashed ); testUsingContext( - 'honors --no-android-gradle-daemon setting', + 'honors --android-project-cache-dir setting', () async { final AndroidGradleBuilder builder = AndroidGradleBuilder( java: FakeJava(), @@ -2265,13 +2230,13 @@ Gradle Crashed command: [ 'gradlew', '-q', - '--no-daemon', '-Ptarget-platform=android-arm,android-arm64,android-x64', '-Ptarget=lib/main.dart', '-Pbase-application-name=android.app.Application', '-Pdart-obfuscation=false', '-Ptrack-widget-creation=false', '-Ptree-shake-icons=false', + '--project-cache-dir=/made/up/dir', 'assembleRelease', ], ), @@ -2298,7 +2263,7 @@ Gradle Crashed BuildMode.release, null, treeShakeIcons: false, - androidGradleDaemon: false, + androidGradleProjectCacheDir: '/made/up/dir', packageConfigPath: '.dart_tool/package_config.json', ), ), @@ -2530,114 +2495,6 @@ Gradle Crashed overrides: {AndroidStudio: () => FakeAndroidStudio()}, ); - testUsingContext( - 'build aar uses selected local engine with x86 ABI', - () async { - final AndroidGradleBuilder builder = AndroidGradleBuilder( - java: FakeJava(), - logger: logger, - processManager: processManager, - fileSystem: fileSystem, - artifacts: Artifacts.testLocalEngine( - localEngine: 'out/android_x86', - localEngineHost: 'out/host_release', - ), - analytics: fakeAnalytics, - gradleUtils: FakeGradleUtils(), - platform: FakePlatform(), - androidStudio: FakeAndroidStudio(), - ); - processManager.addCommand( - const FakeCommand( - command: [ - 'gradlew', - '-I=/packages/flutter_tools/gradle/aar_init_script.gradle', - '-Pflutter-root=/', - '-Poutput-dir=build/', - '-Pis-plugin=false', - '-PbuildNumber=2.0', - '-q', - '-Pdart-obfuscation=false', - '-Ptrack-widget-creation=false', - '-Ptree-shake-icons=false', - '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', - '-Plocal-engine-build-mode=release', - '-Plocal-engine-out=out/android_x86', - '-Plocal-engine-host-out=out/host_release', - '-Ptarget-platform=android-x86', - 'assembleAarRelease', - ], - ), - ); - - fileSystem.file('out/android_x86/flutter_embedding_release.pom') - ..createSync(recursive: true) - ..writeAsStringSync(''' - - - 1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b - - - -'''); - fileSystem.file('out/android_x86/x86_release.pom').createSync(recursive: true); - fileSystem.file('out/android_x86/x86_release.jar').createSync(recursive: true); - fileSystem - .file('out/android_x86/x86_release.maven-metadata.xml') - .createSync(recursive: true); - fileSystem - .file('out/android_x86/flutter_embedding_release.jar') - .createSync(recursive: true); - fileSystem - .file('out/android_x86/flutter_embedding_release.pom') - .createSync(recursive: true); - fileSystem - .file('out/android_x86/flutter_embedding_release.maven-metadata.xml') - .createSync(recursive: true); - - final File manifestFile = fileSystem.file('pubspec.yaml'); - manifestFile.createSync(recursive: true); - manifestFile.writeAsStringSync(''' - flutter: - module: - androidPackage: com.example.test - '''); - - fileSystem.directory('.android/gradle').createSync(recursive: true); - fileSystem.directory('.android/gradle/wrapper').createSync(recursive: true); - fileSystem.file('.android/gradlew').createSync(recursive: true); - fileSystem.file('.android/gradle.properties').writeAsStringSync('irrelevant'); - fileSystem.file('.android/build.gradle').createSync(recursive: true); - fileSystem.directory('build/outputs/repo').createSync(recursive: true); - - await builder.buildGradleAar( - androidBuildInfo: const AndroidBuildInfo( - BuildInfo( - BuildMode.release, - null, - treeShakeIcons: false, - packageConfigPath: '.dart_tool/package_config.json', - ), - ), - project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), - outputDirectory: fileSystem.directory('build/'), - target: '', - buildNumber: '2.0', - ); - - expect( - fileSystem.link( - 'build/outputs/repo/io/flutter/flutter_embedding_release/' - '1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b/' - 'flutter_embedding_release-1.0.0-73fd6b049a80bcea2db1f26c7cee434907cd188b.pom', - ), - exists, - ); - expect(processManager, hasNoRemainingExpectations); - }, - overrides: {AndroidStudio: () => FakeAndroidStudio()}, - ); - testUsingContext( 'build aar uses selected local engine on x64 ABI', () async { diff --git a/packages/flutter_tools/test/general.shard/android/build_validation_test.dart b/packages/flutter_tools/test/general.shard/android/build_validation_test.dart index c32f0ee64f0fa..13eacdbd9acff 100644 --- a/packages/flutter_tools/test/general.shard/android/build_validation_test.dart +++ b/packages/flutter_tools/test/general.shard/android/build_validation_test.dart @@ -8,15 +8,6 @@ import 'package:flutter_tools/src/build_info.dart'; import '../../src/common.dart'; void main() { - testWithoutContext('validateBuild throws if attempting to build release/profile on x86', () { - expect( - () => validateBuild( - const AndroidBuildInfo(BuildInfo.release, targetArchs: [AndroidArch.x86]), - ), - throwsToolExit(message: 'Cannot build release mode for x86 ABI.'), - ); - }); - testWithoutContext('validateBuild does not throw on AOT supported architectures', () { expect( () => validateBuild( @@ -45,7 +36,7 @@ void main() { buildNumber: 'a', packageConfigPath: '.dart_tool/package_config.json', ), - targetArchs: [AndroidArch.x86], + targetArchs: [AndroidArch.x86_64], ), ), throwsToolExit(message: 'buildNumber: a was not a valid integer value.'), @@ -62,7 +53,7 @@ void main() { buildNumber: '-1', packageConfigPath: '.dart_tool/package_config.json', ), - targetArchs: [AndroidArch.x86], + targetArchs: [AndroidArch.x86_64], ), ), throwsToolExit(message: 'buildNumber: -1 must be a positive integer value.'), @@ -79,7 +70,7 @@ void main() { buildNumber: '2100000001', packageConfigPath: '.dart_tool/package_config.json', ), - targetArchs: [AndroidArch.x86], + targetArchs: [AndroidArch.x86_64], ), ), throwsToolExit( @@ -101,7 +92,7 @@ void main() { buildNumber: '2', packageConfigPath: '.dart_tool/package_config.json', ), - targetArchs: [AndroidArch.x86], + targetArchs: [AndroidArch.x86_64], ), ), returnsNormally, 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 2256ff0c1b496..c342d144281ba 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 @@ -316,6 +316,9 @@ void main() { expect(fsUtils.escapePath(r'C:\foo\bar\cool.dart'), r'C:\\foo\\bar\\cool.dart'); expect(fsUtils.escapePath(r'foo\bar\cool.dart'), r'foo\\bar\\cool.dart'); expect(fsUtils.escapePath('C:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); + expect(fsUtils.escapePath('c:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); + expect(fsUtils.escapePath('x:/foo/bar/cool.dart'), 'X:/foo/bar/cool.dart'); + expect(fsUtils.escapePath(r'a:\foo\bar\cool.dart'), r'A:\\foo\\bar\\cool.dart'); }); testWithoutContext('on Linux', () { diff --git a/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart index f0efccaf5e3ef..3855c40141ee8 100644 --- a/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart @@ -17,6 +17,7 @@ void main() { fileSystem = MemoryFileSystem.test(); depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); }); + testWithoutContext('Can parse depfile from file', () { final File depfileSource = fileSystem.file('example.d')..writeAsStringSync(''' a.txt: b.txt @@ -48,22 +49,34 @@ a.txt c.txt d.txt: b.txt }); testWithoutContext('Can parse depfile with windows file paths', () { - fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); - depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); + final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); final File depfileSource = fileSystem.file('example.d')..writeAsStringSync(r''' -C:\\a.txt: C:\\b.txt +C:\\a1.txt C:\\a2/a3.txt: C:\\b1.txt C:\\b2/b3.txt '''); final Depfile depfile = depfileService.parse(depfileSource); - expect(depfile.inputs.single.path, r'C:\b.txt'); - expect(depfile.outputs.single.path, r'C:\a.txt'); + expect(depfile.inputs.map((File e) => e.path).toList(), [ + r'C:\b1.txt', + r'C:\b2\b3.txt', + ]); + expect(depfile.outputs.map((File e) => e.path).toList(), [ + r'C:\a1.txt', + r'C:\a2\a3.txt', + ]); }); testWithoutContext( 'Can escape depfile with windows file paths and spaces in directory names', () { - fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); - depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); + final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); final File inputFile = fileSystem.directory(r'Hello Flutter').childFile('a.txt').absolute ..createSync(recursive: true); @@ -73,8 +86,9 @@ C:\\a.txt: C:\\b.txt final File outputDepfile = fileSystem.file('depfile'); depfileService.writeToFile(depfile, outputDepfile); - expect(outputDepfile.readAsStringSync(), contains(r'C:\\Hello\ Flutter\\a.txt')); - expect(outputDepfile.readAsStringSync(), contains(r'C:\\Hello\ Flutter\\b.txt')); + final String output = outputDepfile.readAsStringSync(); + expect(output, contains(r'C:\\Hello\ Flutter\\a.txt')); + expect(output, contains(r'C:\\Hello\ Flutter\\b.txt')); }, ); @@ -88,8 +102,46 @@ C:\\a.txt: C:\\b.txt final File outputDepfile = fileSystem.file('depfile'); depfileService.writeToFile(depfile, outputDepfile); - expect(outputDepfile.readAsStringSync(), contains(r'/Hello\ Flutter/a.txt')); - expect(outputDepfile.readAsStringSync(), contains(r'/Hello\ Flutter/b.txt')); + final String output = outputDepfile.readAsStringSync(); + expect(output, contains(r'/Hello\ Flutter/a.txt')); + expect(output, contains(r'/Hello\ Flutter/b.txt')); + }); + + testWithoutContext('Can produce normalized paths', () { + final List<(FileSystemStyle style, String input, String output, List expects)> pairs = + <(FileSystemStyle style, String input, String output, List expects)>[ + ( + FileSystemStyle.posix, + r'Hello Flutter\a.txt', + r'Hello Flutter\b.txt', + [r'/Hello\ Flutter/a.txt', r'/Hello\ Flutter/b.txt'], + ), + ( + FileSystemStyle.windows, + r'Hello Flutter/a.txt', + r'Hello Flutter/b.txt', + [r'\\Hello\ Flutter\\a.txt', r'\\Hello\ Flutter\\b.txt'], + ), + ]; + + for (final (FileSystemStyle style, String input, String output, List expects) + in pairs) { + final FileSystem fileSystem = MemoryFileSystem.test(style: style); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); + final File inputFile = fileSystem.file(input).absolute..createSync(recursive: true); + final File outputFile = fileSystem.file(output).absolute..createSync(); + final Depfile depfile = Depfile([inputFile], [outputFile]); + final File outputDepfile = fileSystem.file('depfile'); + depfileService.writeToFile(depfile, outputDepfile); + + final String outputString = outputDepfile.readAsStringSync(); + for (final String path in expects) { + expect(outputString, contains(path)); + } + } }); testWithoutContext('Resilient to weird whitespace', () { 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 2e2ad77efe7b7..1652a6f518b92 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 @@ -13,6 +13,7 @@ import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/common.dart'; import 'package:flutter_tools/src/build_system/targets/ios.dart'; import 'package:flutter_tools/src/compile.dart'; +import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:test/fake.dart'; @@ -440,58 +441,65 @@ void main() { ); testUsingContext( - "tool exits when $kAppFlavor is already set in user's environment", + 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if ios app', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); - final Future buildResult = const KernelSnapshot().build( - androidEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.android) - ..defines[kBuildMode] = BuildMode.debug.cliName - ..defines[kFlavor] = 'strawberry' - ..defines[kTrackWidgetCreation] = 'false', + final String build = iosEnvironment.buildDir.path; + final String flutterPatchedSdkPath = artifacts.getArtifactPath( + Artifact.flutterPatchedSdkPath, + platform: TargetPlatform.ios, + mode: BuildMode.debug, ); - - expect( - buildResult, - throwsToolExit( - message: '$kAppFlavor is used by the framework and cannot be set in the environment.', + fileSystem.directory('/ios/Runner.xcodeproj').createSync(recursive: true); + processManager.addCommands([ + FakeCommand( + command: [ + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), + '--sdk-root', + '$flutterPatchedSdkPath/', + '--target=flutter', + '--no-print-incremental-dependencies', + '-D$kAppFlavor=chocolate', + ...buildModeOptions(BuildMode.debug, []), + '--no-link-platform', + '--packages', + '/.dart_tool/package_config.json', + '--output-dill', + '$build/app.dill', + '--depfile', + '$build/kernel_snapshot_program.d', + '--incremental', + '--initialize-from-dill', + '$build/app.dill', + '--verbosity=error', + 'file:///lib/main.dart', + ], + stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n', ), - ); - }, - overrides: { - Platform: () => FakePlatform(environment: {kAppFlavor: 'I was already set'}), - }, - ); + ]); - testUsingContext( - 'tool exits when $kAppFlavor is set in --dart-define or --dart-define-from-file', - () async { - fileSystem.file('.dart_tool/package_config.json') - ..createSync(recursive: true) - ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); - final Future buildResult = const KernelSnapshot().build( - androidEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.android) + await const KernelSnapshot().build( + iosEnvironment + ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.ios) ..defines[kBuildMode] = BuildMode.debug.cliName ..defines[kFlavor] = 'strawberry' - ..defines[kDartDefines] = encodeDartDefines([kAppFlavor, 'strawberry']) + ..defines[kXcodeConfiguration] = 'Debug-chocolate' ..defines[kTrackWidgetCreation] = 'false', ); - expect( - buildResult, - throwsToolExit( - message: - '$kAppFlavor is used by the framework and cannot be set using --dart-define or --dart-define-from-file', - ), - ); + expect(processManager, hasNoRemainingExpectations); + }, + overrides: { + XcodeProjectInterpreter: + () => FakeXcodeProjectInterpreter(schemes: ['Runner', 'chocolate']), }, ); testUsingContext( - 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if ios app', + 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if macos app', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) @@ -499,10 +507,10 @@ void main() { final String build = iosEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, - platform: TargetPlatform.ios, + platform: TargetPlatform.darwin, mode: BuildMode.debug, ); - fileSystem.directory('/ios/Runner.xcodeproj').createSync(recursive: true); + fileSystem.directory('/macos/Runner.xcodeproj').createSync(recursive: true); processManager.addCommands([ FakeCommand( command: [ @@ -514,7 +522,6 @@ void main() { '--no-print-incremental-dependencies', '-D$kAppFlavor=chocolate', ...buildModeOptions(BuildMode.debug, []), - '--no-link-platform', '--packages', '/.dart_tool/package_config.json', '--output-dill', @@ -533,7 +540,7 @@ void main() { await const KernelSnapshot().build( iosEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.ios) + ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin) ..defines[kBuildMode] = BuildMode.debug.cliName ..defines[kFlavor] = 'strawberry' ..defines[kXcodeConfiguration] = 'Debug-chocolate' @@ -549,7 +556,7 @@ void main() { ); testUsingContext( - 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if macos app', + 'KernelSnapshot does not add kAppFlavor twice to Dart defines', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) @@ -560,7 +567,6 @@ void main() { platform: TargetPlatform.darwin, mode: BuildMode.debug, ); - fileSystem.directory('/macos/Runner.xcodeproj').createSync(recursive: true); processManager.addCommands([ FakeCommand( command: [ @@ -570,7 +576,7 @@ void main() { '$flutterPatchedSdkPath/', '--target=flutter', '--no-print-incremental-dependencies', - '-D$kAppFlavor=chocolate', + '-D$kAppFlavor=strawberry', ...buildModeOptions(BuildMode.debug, []), '--packages', '/.dart_tool/package_config.json', @@ -592,16 +598,17 @@ void main() { iosEnvironment ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin) ..defines[kBuildMode] = BuildMode.debug.cliName + ..defines[kDartDefines] = base64Encode(utf8.encode('FLUTTER_APP_FLAVOR=vanilla')) ..defines[kFlavor] = 'strawberry' - ..defines[kXcodeConfiguration] = 'Debug-chocolate' ..defines[kTrackWidgetCreation] = 'false', ); expect(processManager, hasNoRemainingExpectations); }, overrides: { - XcodeProjectInterpreter: - () => FakeXcodeProjectInterpreter(schemes: ['Runner', 'chocolate']), + Platform: () => macPlatform, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }, ); 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 a342f441eb436..8e9af0ca324c4 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 @@ -7,13 +7,11 @@ import 'dart:async'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/ios.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; @@ -49,32 +47,6 @@ const List _kSharedConfig = [ 'path/to/iPhoneOS.sdk', ]; -const String _kPluginsFileWithoutDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": false - } - ] - } -} -'''; - -const String _kPluginsFileWithDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": true - } - ] - } -} -'''; - void main() { late Environment environment; late MemoryFileSystem fileSystem; @@ -983,6 +955,87 @@ void main() { ); }); + group('CheckForLaunchRootViewControllerAccessDeprecation', () { + testWithoutContext('Swift Positive', () async { + final File file = fileSystem.file('AppDelegate.swift'); + file.writeAsStringSync(''' +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + } +} +'''); + await checkForLaunchRootViewControllerAccessDeprecationSwift(logger, file); + expect( + logger.warningText, + startsWith( + 'AppDelegate.swift:6: warning: Flutter deprecation: Accessing rootViewController', + ), + ); + }); + + testWithoutContext('Swift Negative', () async { + final File file = fileSystem.file('AppDelegate.swift'); + file.writeAsStringSync(''' +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + } + + func doIt() { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + } +} +'''); + await checkForLaunchRootViewControllerAccessDeprecationSwift(logger, file); + expect(logger.warningText, equals('')); + }); + + testWithoutContext('Objc Positive', () async { + final File file = fileSystem.file('AppDelegate.m'); + file.writeAsStringSync(''' +@implementation AppDelegate + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + FlutterViewController* controller = + (FlutterViewController*)self.window.rootViewController; +} + +@end +'''); + await checkForLaunchRootViewControllerAccessDeprecationObjc(logger, file); + expect( + logger.warningText, + startsWith('AppDelegate.m:6: warning: Flutter deprecation: Accessing rootViewController'), + ); + }); + + testWithoutContext('Objc Negative', () async { + final File file = fileSystem.file('AppDelegate.m'); + file.writeAsStringSync(''' +@implementation AppDelegate + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { +} + +- (void)doIt { + FlutterViewController* controller = + (FlutterViewController*)self.window.rootViewController; +} + +@end +'''); + await checkForLaunchRootViewControllerAccessDeprecationObjc(logger, file); + expect(logger.warningText, equals('')); + }); + }); + testWithoutContext('skips thin framework', () async { binary.createSync(recursive: true); @@ -1274,161 +1327,6 @@ void main() { }, ); }); - - group('CheckDevDependenciesIos', () { - testUsingContext('throws if build mode define missing', () async { - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('throws if dev dependencies define missing', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'debug'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('does not throw if dev dependencies enabled in debug mode', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in release mode', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in profile mode', () async { - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if there are no dependencies', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if there are no dev dependencies', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithoutDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - - expect( - logger.traceText, - contains('Ignoring dev dependencies error as the project has no dev dependencies'), - ); - }); - - testUsingContext('throws if dev dependencies disabled in debug mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies enabled in release mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies enabled in release build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies disabled in profile mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'profile'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in profile build'), - ), - ), - ); - }); - - testUsingContext( - 'assumes project has dev dependencies if .flutter-plugins-dependencies is malformed', - () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync('This is not valid JSON'); - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }, - ); - }); } class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/localizations_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/localizations_test.dart index 80e30ff06cd4f..7a30f2c9efa35 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/localizations_test.dart @@ -43,7 +43,6 @@ header-file: header header: HEADER use-deferred-loading: true preferred-supported-locales: en_US -synthetic-package: false required-resource-attributes: false nullable-getter: false '''); @@ -53,7 +52,6 @@ nullable-getter: false logger: BufferLogger.test(), fileSystem: fileSystem, defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: true, ); expect(options.arbDir, Uri.parse('arb').path); @@ -65,15 +63,15 @@ nullable-getter: false expect(options.header, 'HEADER'); expect(options.useDeferredLoading, true); expect(options.preferredSupportedLocales, ['en_US']); - expect(options.syntheticPackage, false); expect(options.requiredResourceAttributes, false); expect(options.nullableGetter, false); }); - testWithoutContext('parseLocalizationsOptions uses defaultSyntheticPackage = true', () async { + testWithoutContext('parseLocalizationsOptions refuses synthetic-package: true', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final File configFile = fileSystem.file('l10n.yaml')..writeAsStringSync(''' arb-dir: arb +synthetic-package: true template-arb-file: example.arb output-localization-file: bar untranslated-messages-file: untranslated @@ -82,27 +80,26 @@ header-file: header header: HEADER use-deferred-loading: true preferred-supported-locales: en_US -# Intentionally omitted -# synthetic-package: ... required-resource-attributes: false nullable-getter: false '''); - final LocalizationOptions options = parseLocalizationsOptionsFromYAML( - file: configFile, - logger: BufferLogger.test(), - fileSystem: fileSystem, - defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: true, + expect( + () => parseLocalizationsOptionsFromYAML( + file: configFile, + logger: BufferLogger.test(), + fileSystem: fileSystem, + defaultArbDir: fileSystem.path.join('lib', 'l10n'), + ), + throwsToolExit(message: 'synthetic-package'), ); - - expect(options.syntheticPackage, true); }); - testWithoutContext('parseLocalizationsOptions uses defaultSyntheticPackage = false', () async { + testWithoutContext('parseLocalizationsOptions warns on synthetic-package: false', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final File configFile = fileSystem.file('l10n.yaml')..writeAsStringSync(''' arb-dir: arb +synthetic-package: false template-arb-file: example.arb output-localization-file: bar untranslated-messages-file: untranslated @@ -111,21 +108,22 @@ header-file: header header: HEADER use-deferred-loading: true preferred-supported-locales: en_US -# Intentionally omitted -# synthetic-package: ... required-resource-attributes: false nullable-getter: false '''); - final LocalizationOptions options = parseLocalizationsOptionsFromYAML( - file: configFile, - logger: BufferLogger.test(), - fileSystem: fileSystem, - defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: false, + final BufferLogger logger = BufferLogger.test(); + expect( + () => parseLocalizationsOptionsFromYAML( + file: configFile, + logger: logger, + fileSystem: fileSystem, + defaultArbDir: fileSystem.path.join('lib', 'l10n'), + ), + returnsNormally, ); - expect(options.syntheticPackage, false); + expect(logger.warningText, contains('synthetic-package')); }); testWithoutContext( @@ -141,7 +139,6 @@ preferred-supported-locales: ['en_US', 'de'] logger: BufferLogger.test(), fileSystem: fileSystem, defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: true, ); expect(options.preferredSupportedLocales, ['en_US', 'de']); @@ -162,7 +159,6 @@ use-deferred-loading: string logger: BufferLogger.test(), fileSystem: fileSystem, defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: true, ), throwsException, ); @@ -181,7 +177,6 @@ template-arb-file: {name}_en.arb logger: BufferLogger.test(), fileSystem: fileSystem, defaultArbDir: fileSystem.path.join('lib', 'l10n'), - defaultSyntheticPackage: true, ), throwsToolExit(), ); 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 9ffe1850010f6..e57483454f1af 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 @@ -5,12 +5,10 @@ import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/macos.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:test/fake.dart'; @@ -22,32 +20,6 @@ import '../../../src/fake_process_manager.dart'; import '../../../src/fakes.dart'; import '../../../src/package_config.dart'; -const String _kPluginsFileWithoutDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": false - } - ] - } -} -'''; - -const String _kPluginsFileWithDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": true - } - ] - } -} -'''; - void main() { late Environment environment; late MemoryFileSystem fileSystem; @@ -997,162 +969,6 @@ void main() { ProcessManager: () => processManager, }, ); - - group('CheckDevDependenciesMacOS', () { - testUsingContext('throws if build mode define missing', () async { - environment.defines.remove(kBuildMode); - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('throws if dev dependencies define missing', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'debug'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('does not throw if dev dependencies enabled in debug mode', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in release mode', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in profile mode', () async { - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if there are no dependencies', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if there are no dev dependencies', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithoutDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - - expect( - logger.traceText, - contains('Ignoring dev dependencies error as the project has no dev dependencies'), - ); - }); - - testUsingContext('throws if dev dependencies disabled in debug mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies enabled in release mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies enabled in release build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies disabled in profile mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'profile'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in profile build'), - ), - ), - ); - }); - - testUsingContext( - 'assumes project has dev dependencies if .flutter-plugins-dependencies is malformed', - () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync('This is not valid JSON'); - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }, - ); - }); } class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 13a2f6e361763..8033697e59d0b 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -32,6 +32,12 @@ const List _kDart2jsLinuxArgs = [ '--invoker=flutter_tool', ]; +const List _kStandardFlutterWebDefines = [ + '-DFLUTTER_WEB_USE_SKIA=true', + '-DFLUTTER_WEB_USE_SKWASM=false', + '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', +]; + const List _kDart2WasmLinuxArgs = [ 'Artifact.engineDartBinary.TargetPlatform.web_javascript', 'compile', @@ -514,16 +520,20 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with csp', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '--csp', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -534,16 +544,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '--csp', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -558,15 +559,18 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with minify false', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -577,14 +581,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -600,16 +597,19 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kFrontendServerStarterPath] = 'path/to/frontend_server_starter.dart'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -620,15 +620,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -644,17 +636,20 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kExtraFrontEndOptions] = '--enable-experiment=non-nullable'; + final List common = [ + ..._kDart2jsLinuxArgs, + '--enable-experiment=non-nullable', + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '--enable-experiment=non-nullable', - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -665,16 +660,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '--enable-experiment=non-nullable', - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -689,16 +675,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in profile mode', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -709,15 +698,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -732,16 +713,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release mode', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -752,15 +736,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -775,17 +751,20 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release mode with native null assertions', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--native-null-assertions', + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--native-null-assertions', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -796,16 +775,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--native-null-assertions', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -822,16 +792,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O3', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -842,15 +815,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O3', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -867,16 +832,19 @@ name: foo 'Dart2JSTarget produces expected depfile', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -890,15 +858,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -925,18 +885,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -947,17 +910,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -973,15 +926,18 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; environment.defines[WebCompilerConfig.kSourceMapsEnabled] = 'true'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -992,14 +948,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1015,18 +964,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1037,17 +989,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1063,18 +1005,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'debug'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '--enable-asserts', + '-O1', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '--enable-asserts', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1085,17 +1030,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '--enable-asserts', - '-O1', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1110,15 +1045,18 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with dump-info', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', + ...common, '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1130,14 +1068,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', + ...common, '--stage=dump-info-all', '-o', environment.buildDir.childFile('main.dart.js').absolute.path, @@ -1156,16 +1087,22 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with no-frequency-based-minification', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '--no-frequency-based-minification', + '-o', + ]; + processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1176,16 +1113,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '--no-frequency-based-minification', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index ee0aa1c45cb49..d38f1b5baa1fa 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -527,14 +527,14 @@ void main() { }, ); - testWithoutContext('IosUsbArtifacts verifies iproxy for usbmuxd in isUpToDateInner', () async { + testWithoutContext('IosUsbArtifacts verifies iproxy for libusbmuxd in isUpToDateInner', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final Cache cache = Cache.test( fileSystem: fileSystem, processManager: FakeProcessManager.any(), ); final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts( - 'usbmuxd', + 'libusbmuxd', cache, platform: FakePlatform(operatingSystem: 'macos'), ); @@ -1414,11 +1414,11 @@ class FakePub extends Fake implements Pub { required FlutterProject project, bool upgrade = false, bool offline = false, - bool generateSyntheticPackage = false, String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, + bool enforceLockfile = false, PubOutputMode outputMode = PubOutputMode.all, }) async { invocations.add(FakePubInvocation(outputMode: outputMode)); diff --git a/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart b/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart deleted file mode 100644 index 0f61051fc7126..0000000000000 --- a/packages/flutter_tools/test/general.shard/dart/generate_synthetic_packages_test.dart +++ /dev/null @@ -1,560 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; - -import 'package:file/memory.dart'; -import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/build_targets.dart'; -import 'package:flutter_tools/src/build_system/targets/localizations.dart'; -import 'package:flutter_tools/src/dart/generate_synthetic_packages.dart'; -import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/isolated/build_targets.dart'; - -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; -import '../../src/test_build_system.dart'; - -void main() { - // TODO(matanlurey): Remove after support for flutter_gen is removed. - // See https://github.com/flutter/flutter/issues/102983 for details. - FeatureFlags disableExplicitPackageDependencies() { - // ignore: avoid_redundant_argument_values - return TestFeatureFlags(isExplicitPackageDependenciesEnabled: false); - } - - testUsingContext( - 'calls buildSystem.build with blank l10n.yaml file', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').createSync(); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Artifacts artifacts = Artifacts.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: artifacts, - processManager: FakeProcessManager.any(), - ); - final Completer completer = Completer(); - final BuildResult exception = BuildResult( - success: false, - exceptions: { - 'hello': ExceptionMeasurement( - 'hello', - const FormatException('illegal character in input string'), - StackTrace.current, - ), - }, - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(exception, ( - Target target, - Environment environment, - ) { - expect(target, const GenerateLocalizationsTarget()); - expect(environment, environment); - completer.complete(); - }); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ), - throwsToolExit( - message: - 'Generating synthetic localizations package failed with 1 error:' - '\n\n' - 'FormatException: illegal character in input string', - ), - ); - await completer.future; - }, - overrides: {FeatureFlags: disableExplicitPackageDependencies}, - ); - - testUsingContext( - 'calls buildSystem.build with l10n.yaml synthetic-package: true', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: true'); - - final FakeProcessManager fakeProcessManager = FakeProcessManager.any(); - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Artifacts artifacts = Artifacts.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: artifacts, - processManager: fakeProcessManager, - ); - final Completer completer = Completer(); - final BuildResult exception = BuildResult( - success: false, - exceptions: { - 'hello': ExceptionMeasurement( - 'hello', - const FormatException('illegal character in input string'), - StackTrace.current, - ), - }, - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(exception, ( - Target target, - Environment environment, - ) { - expect(target, const GenerateLocalizationsTarget()); - expect(environment, environment); - completer.complete(); - }); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ), - throwsToolExit( - message: - 'Generating synthetic localizations package failed with 1 error:' - '\n\n' - 'FormatException: illegal character in input string', - ), - ); - await completer.future; - }, - overrides: {FeatureFlags: disableExplicitPackageDependencies}, - ); - - testUsingContext( - 'calls buildSystem.build with l10n.yaml synthetic-package: null', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: null'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - final Completer completer = Completer(); - final BuildResult exception = BuildResult( - success: false, - exceptions: { - 'hello': ExceptionMeasurement( - 'hello', - const FormatException('illegal character in input string'), - StackTrace.current, - ), - }, - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(exception, ( - Target target, - Environment environment, - ) { - expect(target, const GenerateLocalizationsTarget()); - expect(environment, environment); - completer.complete(); - }); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ), - throwsToolExit( - message: - 'Generating synthetic localizations package failed with 1 error:' - '\n\n' - 'FormatException: illegal character in input string', - ), - ); - await completer.future; - }, - overrides: {FeatureFlags: disableExplicitPackageDependencies}, - ); - - testUsingContext('does not call buildSystem.build when l10n.yaml is not present', () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - // Will throw if build is called. - final TestBuildSystem buildSystem = TestBuildSystem.all(null); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ); - }); - - testUsingContext('does not call buildSystem.build with incorrect l10n.yaml format', () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync('helloWorld'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - // Will throw if build is called. - final TestBuildSystem buildSystem = TestBuildSystem.all(null); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ), - throwsToolExit(message: 'to contain a map, instead was helloWorld'), - ); - }); - - testUsingContext( - 'does not call buildSystem.build with non-bool "synthetic-package" value', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: nonBoolValue'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - // Will throw if build is called. - final TestBuildSystem buildSystem = TestBuildSystem.all(null); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ), - throwsToolExit(message: 'to have a bool value, instead was "nonBoolValue"'), - ); - }, - ); - - testUsingContext( - 'synthetic-package: true (implicit) logs a deprecation warning', - () async { - // Project directory setup for gen_l10n logic. - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create a blank l10n.yaml file. - fileSystem.file('l10n.yaml').writeAsStringSync(''); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ); - - expect( - mockBufferLogger.warningText, - contains('https://flutter.dev/to/flutter-gen-deprecation'), - ); - }, - overrides: {FeatureFlags: disableExplicitPackageDependencies}, - ); - - testUsingContext( - 'synthetic-package: true (explicit) logs a deprecation warning', - () async { - // Project directory setup for gen_l10n logic. - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: true'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ); - - expect( - mockBufferLogger.warningText, - contains('https://flutter.dev/to/flutter-gen-deprecation'), - ); - }, - overrides: {FeatureFlags: disableExplicitPackageDependencies}, - ); - - testUsingContext('synthetic-package: false has no deprecation warning', () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: false'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const BuildTargetsImpl(), - ); - - expect( - mockBufferLogger.warningText, - isNot(contains('https://flutter.dev/to/flutter-gen-deprecation')), - ); - }); - - testUsingContext( - 'synthetic-package omitted with explicit-package-dependencies is a NOP', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.empty(), - ); - final TestBuildSystem buildSystem = TestBuildSystem.all(BuildResult(success: true)); - - await generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ); - - expect( - mockBufferLogger.warningText, - isNot(contains('https://flutter.dev/to/flutter-gen-deprecation')), - ); - }, - ); - - testUsingContext( - 'synthetic-package: true with explicit-packages-resolution is an error', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync('synthetic-package: true'); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - // Will throw if build is called. - final TestBuildSystem buildSystem = TestBuildSystem.all(null); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ), - throwsToolExit( - message: - 'Cannot generate a synthetic package when explicit-package-dependencies is enabled', - ), - ); - }, - ); - - testUsingContext( - 'synthetic-package defaults to false if explicit-package-dependencies is enabled', - () async { - // Project directory setup for gen_l10n logic - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - - // Add generate:true to pubspec.yaml. - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - final String content = pubspecFile.readAsStringSync().replaceFirst( - '\nflutter:\n', - '\nflutter:\n generate: true\n', - ); - pubspecFile.writeAsStringSync(content); - - // Create an l10n.yaml file - fileSystem.file('l10n.yaml').writeAsStringSync(''); - - final BufferLogger mockBufferLogger = BufferLogger.test(); - final Environment environment = Environment.test( - fileSystem.currentDirectory, - fileSystem: fileSystem, - logger: mockBufferLogger, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.any(), - ); - // Will throw if build is called. - final TestBuildSystem buildSystem = TestBuildSystem.all(null); - - await expectLater( - () => generateLocalizationsSyntheticPackage( - environment: environment, - buildSystem: buildSystem, - buildTargets: const NoOpBuildTargets(), - ), - returnsNormally, - ); - }, - ); -} diff --git a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart index 925462d92a72f..1bf4f5dec3797 100644 --- a/packages/flutter_tools/test/general.shard/dart_plugin_test.dart +++ b/packages/flutter_tools/test/general.shard/dart_plugin_test.dart @@ -35,7 +35,6 @@ void main() { FakeFlutterProject() ..manifest = flutterManifest ..directory = directory - ..flutterPluginsFile = directory.childFile('.flutter-plugins') ..flutterPluginsDependenciesFile = directory.childFile('.flutter-plugins-dependencies') ..dartPluginRegistrant = directory.childFile('dart_plugin_registrant.dart'); writePackageConfigFiles(directory: flutterProject.directory, mainLibName: 'my_app'); @@ -1485,9 +1484,6 @@ class FakeFlutterProject extends Fake implements FlutterProject { @override File get packageConfig => directory.childDirectory('.dart_tool').childFile('package_config.json'); - @override - late File flutterPluginsFile; - @override late File flutterPluginsDependenciesFile; diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart index d8fe50e907dd4..65ed19f611b27 100644 --- a/packages/flutter_tools/test/general.shard/features_test.dart +++ b/packages/flutter_tools/test/general.shard/features_test.dart @@ -124,6 +124,19 @@ void main() { FileSystem: createFsWithPubspec, }, ); + + testUsingContext('Test feature flags match feature flags', () { + final FeatureFlags testFeatureFlags = TestFeatureFlags(); + + expect(featureFlags.allFeatures.length, equals(testFeatureFlags.allFeatures.length)); + + final List featureNames = + featureFlags.allFeatures.map((Feature feature) => feature.name).toList(); + final List testFeatureNames = + testFeatureFlags.allFeatures.map((Feature feature) => feature.name).toList(); + + expect(featureNames, unorderedEquals(testFeatureNames)); + }); }); group('Linux Destkop', () { @@ -441,4 +454,7 @@ final class _TestIsGetterForwarding with FlutterFeatureFlagsIsEnabled { bool isEnabled(Feature feature) { return feature == shouldInvoke; } + + @override + List get allFeatures => throw UnimplementedError(); } diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart index 46f56175c6dab..9b499af59c039 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -708,7 +708,6 @@ flutter: arbDir: Uri.directory(defaultL10nPath).path, outputDir: Uri.directory(defaultL10nPath, windows: false).path, templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false).path, - syntheticPackage: false, ), logger: logger, projectDir: projectDir, @@ -731,7 +730,6 @@ flutter: arbDir: Uri.directory(defaultL10nPath).path, outputDir: Uri.directory(defaultL10nPath, windows: false).path, templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false).path, - syntheticPackage: false, ), logger: logger, projectDir: fs.currentDirectory, @@ -753,7 +751,6 @@ flutter: preferredSupportedLocales: ['es'], templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false).path, untranslatedMessagesFile: Uri.file('untranslated', windows: false).path, - syntheticPackage: false, requiredResourceAttributes: true, nullableGetter: false, ); @@ -778,7 +775,6 @@ flutter: expect(generator.header, 'HEADER'); expect(generator.useDeferredLoading, isTrue); expect(generator.inputsAndOutputsListFile?.path, '/gen_l10n_inputs_and_outputs.json'); - expect(generator.useSyntheticPackage, isFalse); expect(generator.projectDirectory?.path, '/'); expect(generator.areResourceAttributesRequired, isTrue); expect(generator.untranslatedMessagesFile?.path, 'untranslated'); @@ -883,7 +879,6 @@ flutter:\r arbDir: Uri.directory(defaultL10nPath).path, outputDir: Uri.directory(defaultL10nPath, windows: false).path, templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false).path, - syntheticPackage: false, ), logger: BufferLogger.test(), projectDir: fs.currentDirectory, @@ -916,7 +911,6 @@ class AppLocalizationsEn extends AppLocalizations { arbDir: Uri.directory(defaultL10nPath).path, outputDir: Uri.directory(defaultL10nPath, windows: false).path, templateArbFile: Uri.file(defaultTemplateArbFileName, windows: false).path, - syntheticPackage: false, ), logger: logger, projectDir: fs.currentDirectory, diff --git a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart index 1ccdae1b2270e..99992c236fa56 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart @@ -14,6 +14,7 @@ import 'package:flutter_tools/src/ios/migrations/project_build_location_migratio import 'package:flutter_tools/src/ios/migrations/remove_bitcode_migration.dart'; import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart'; import 'package:flutter_tools/src/ios/migrations/uiapplicationmain_deprecation_migration.dart'; +import 'package:flutter_tools/src/ios/migrations/uiscenedelegate_migration.dart'; import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/migrations/cocoapods_script_symlink.dart'; @@ -869,6 +870,59 @@ platform :ios, '13.0' expect(testLogger.statusText, isEmpty); }); + testWithoutContext('UISceneDelegate migration', () async { + const String xmlString = ''' + + + + + MyKey + MyValue + UIMainStoryboardFile + Main + + +'''; + infoPlistFile.writeAsStringSync(xmlString); + + final UISceneDelegateMigration migration = UISceneDelegateMigration(project, testLogger); + await migration.migrate(); + + expect(infoPlistFile.readAsStringSync(), ''' + + + + + MyKey + MyValue + UIMainStoryboardFile + Main + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + + + +'''); + }); + testWithoutContext('info.plist is migrated', () async { const String infoPlistFileContent = ''' diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index 717953eba9498..fdd5e23d7db48 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -834,9 +834,6 @@ class FakeFlutterProject extends Fake implements FlutterProject { @override late FlutterManifest manifest; - @override - File get flutterPluginsFile => directory.childFile('.flutter-plugins'); - @override File get flutterPluginsDependenciesFile => directory.childFile('.flutter-plugins-dependencies'); diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 427748f2b15dd..bb8ffeedf24e3 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -10,7 +10,6 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/ios/xcode_build_settings.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/project.dart'; @@ -19,7 +18,6 @@ import 'package:unified_analytics/unified_analytics.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/fake_process_manager.dart'; -import '../../src/fakes.dart'; const String xcodebuild = '/usr/bin/xcodebuild'; @@ -1109,7 +1107,6 @@ Information about project "Runner": late Artifacts localIosArtifacts; late FakePlatform macOS; late FileSystem fs; - late FeatureFlags featureFlags; setUp(() { fs = MemoryFileSystem.test(); @@ -1119,7 +1116,6 @@ Information about project "Runner": ); macOS = FakePlatform(operatingSystem: 'macos'); fs.file(xcodebuild).createSync(recursive: true); - featureFlags = TestFeatureFlags(); }); group('arm simulator', () { @@ -1176,11 +1172,7 @@ Build settings for action build and target plugin2: ''', ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1232,11 +1224,7 @@ Build settings for action build and target plugin2: exitCode: 1, ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1300,11 +1288,7 @@ Build settings for action build and target plugin2: ''', ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1347,11 +1331,7 @@ Build settings for action build and target plugin2: fs.directory('path/to/project'), ); await expectLater( - () => updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ), + () => updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo), throwsToolExit(message: '32-bit iOS local engine binaries are not supported.'), ); }); @@ -1366,7 +1346,7 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + useMacOSConfig: true, ); @@ -1408,7 +1388,7 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + useMacOSConfig: true, ); @@ -1445,11 +1425,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.readAsStringSync(), contains('EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386\n')); @@ -1468,11 +1444,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1502,11 +1474,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1532,11 +1500,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1571,11 +1535,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1627,7 +1587,6 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: FlutterProject.fromDirectoryTest(fs.directory('path/to/project')), buildInfo: buildInfo, - featureFlags: featureFlags, ); final File localPropertiesFile = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); @@ -1865,7 +1824,7 @@ flutter: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + configurationBuildDir: 'path/to/project/build/ios/iphoneos', ); @@ -1891,11 +1850,7 @@ flutter: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); diff --git a/packages/flutter_tools/test/general.shard/macos/cocoapod_utils_test.dart b/packages/flutter_tools/test/general.shard/macos/cocoapod_utils_test.dart index d2425df416176..8ba79e74415eb 100644 --- a/packages/flutter_tools/test/general.shard/macos/cocoapod_utils_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/cocoapod_utils_test.dart @@ -35,7 +35,6 @@ void main() { flutterProject ..manifest = FakeFlutterManifest() ..directory = fileSystem.systemTempDirectory.childDirectory('app') - ..flutterPluginsFile = flutterProject.directory.childFile('.flutter-plugins') ..flutterPluginsDependenciesFile = flutterProject.directory.childFile( '.flutter-plugins-dependencies', ) @@ -452,9 +451,6 @@ class FakeFlutterProject extends Fake implements FlutterProject { @override late Directory directory; - @override - late File flutterPluginsFile; - @override late File flutterPluginsDependenciesFile; @@ -506,12 +502,20 @@ class FakeMacOSProject extends Fake implements MacOSProject { hostAppRoot.childDirectory('Runner.xcodeproj').childFile('project.pbxproj'); @override - File get flutterPluginSwiftPackageManifest => hostAppRoot - .childDirectory('Flutter') - .childDirectory('ephemeral') - .childDirectory('Packages') - .childDirectory('FlutterGeneratedPluginSwiftPackage') - .childFile('Package.swift'); + Directory get flutterSwiftPackagesDirectory => + hostAppRoot.childDirectory('Flutter').childDirectory('ephemeral').childDirectory('Packages'); + + @override + Directory get relativeSwiftPackagesDirectory => + flutterSwiftPackagesDirectory.childDirectory('.packages'); + + @override + Directory get flutterPluginSwiftPackageDirectory => + flutterSwiftPackagesDirectory.childDirectory('FlutterGeneratedPluginSwiftPackage'); + + @override + File get flutterPluginSwiftPackageManifest => + flutterPluginSwiftPackageDirectory.childFile('Package.swift'); @override bool usesSwiftPackageManager = false; @@ -547,12 +551,20 @@ class FakeIosProject extends Fake implements IosProject { hostAppRoot.childDirectory('Runner.xcodeproj').childFile('project.pbxproj'); @override - File get flutterPluginSwiftPackageManifest => hostAppRoot - .childDirectory('Flutter') - .childDirectory('ephemeral') - .childDirectory('Packages') - .childDirectory('FlutterGeneratedPluginSwiftPackage') - .childFile('Package.swift'); + Directory get flutterSwiftPackagesDirectory => + hostAppRoot.childDirectory('Flutter').childDirectory('ephemeral').childDirectory('Packages'); + + @override + Directory get relativeSwiftPackagesDirectory => + flutterSwiftPackagesDirectory.childDirectory('.packages'); + + @override + Directory get flutterPluginSwiftPackageDirectory => + flutterSwiftPackagesDirectory.childDirectory('FlutterGeneratedPluginSwiftPackage'); + + @override + File get flutterPluginSwiftPackageManifest => + flutterPluginSwiftPackageDirectory.childFile('Package.swift'); @override bool usesSwiftPackageManager = false; diff --git a/packages/flutter_tools/test/general.shard/macos/swift_package_manager_test.dart b/packages/flutter_tools/test/general.shard/macos/swift_package_manager_test.dart index 5c15b095547cf..143a595c7817c 100644 --- a/packages/flutter_tools/test/general.shard/macos/swift_package_manager_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/swift_package_manager_test.dart @@ -4,6 +4,7 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/isolated/mustache_template.dart'; import 'package:flutter_tools/src/macos/swift_package_manager.dart'; import 'package:flutter_tools/src/platform_plugins.dart'; @@ -118,13 +119,15 @@ $_doubleIndent fileSystem: fs, ); - final File validPlugin1Manifest = fs.file( - '/local/path/to/plugins/valid_plugin_1/Package.swift', - )..createSync(recursive: true); + final Directory validPlugin1Directory = fs.directory( + '/local/path/to/plugins/valid_plugin_1', + ); + validPlugin1Directory.childFile('Package.swift').createSync(recursive: true); + final FakePlugin validPlugin1 = FakePlugin( name: 'valid_plugin_1', platforms: {platform.name: FakePluginPlatform()}, - pluginSwiftPackageManifestPath: validPlugin1Manifest.path, + pluginSwiftPackagePath: validPlugin1Directory.path, ); final SwiftPackageManager spm = SwiftPackageManager( fileSystem: fs, @@ -135,6 +138,11 @@ $_doubleIndent final String supportedPlatform = platform == SupportedPlatform.ios ? '.iOS("13.0")' : '.macOS("10.15")'; expect(project.flutterPluginSwiftPackageManifest.existsSync(), isTrue); + expect(project.relativeSwiftPackagesDirectory.childLink('valid_plugin_1'), exists); + expect( + project.relativeSwiftPackagesDirectory.childLink('valid_plugin_1').targetSync(), + validPlugin1Directory.path, + ); expect(project.flutterPluginSwiftPackageManifest.readAsStringSync(), ''' // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -153,7 +161,7 @@ let package = Package( .library(name: "FlutterGeneratedPluginSwiftPackage", type: .static, targets: ["FlutterGeneratedPluginSwiftPackage"]) ], dependencies: [ - .package(name: "valid_plugin_1", path: "/local/path/to/plugins/valid_plugin_1") + .package(name: "valid_plugin_1", path: "../.packages/valid_plugin_1") ], targets: [ .target( @@ -176,34 +184,38 @@ let package = Package( final FakePlugin nonPlatformCompatiblePlugin = FakePlugin( name: 'invalid_plugin_due_to_incompatible_platform', platforms: {}, - pluginSwiftPackageManifestPath: '/some/path', + pluginSwiftPackagePath: '/some/path', ); final FakePlugin pluginSwiftPackageManifestIsNull = FakePlugin( name: 'invalid_plugin_due_to_null_plugin_swift_package_path', platforms: {platform.name: FakePluginPlatform()}, - pluginSwiftPackageManifestPath: null, + pluginSwiftPackagePath: null, ); final FakePlugin pluginSwiftPackageManifestNotExists = FakePlugin( name: 'invalid_plugin_due_to_plugin_swift_package_path_does_not_exist', platforms: {platform.name: FakePluginPlatform()}, - pluginSwiftPackageManifestPath: '/some/path', + pluginSwiftPackagePath: '/some/path', ); - final File validPlugin1Manifest = fs.file( - '/local/path/to/plugins/valid_plugin_1/Package.swift', - )..createSync(recursive: true); + final Directory validPlugin1Directory = fs.directory( + '/local/path/to/plugins/valid_plugin_1', + ); + validPlugin1Directory.childFile('Package.swift').createSync(recursive: true); final FakePlugin validPlugin1 = FakePlugin( name: 'valid_plugin_1', platforms: {platform.name: FakePluginPlatform()}, - pluginSwiftPackageManifestPath: validPlugin1Manifest.path, + pluginSwiftPackagePath: validPlugin1Directory.path, ); - final File validPlugin2Manifest = fs.file( - '/.pub-cache/plugins/valid_plugin_2/Package.swift', - )..createSync(recursive: true); + + final Directory validPlugin2Directory = fs.directory( + '/.pub-cache/plugins/valid_plugin_2', + ); + validPlugin2Directory.childFile('Package.swift').createSync(recursive: true); + final FakePlugin validPlugin2 = FakePlugin( name: 'valid_plugin_2', platforms: {platform.name: FakePluginPlatform()}, - pluginSwiftPackageManifestPath: validPlugin2Manifest.path, + pluginSwiftPackagePath: validPlugin2Directory.path, ); final SwiftPackageManager spm = SwiftPackageManager( @@ -225,6 +237,16 @@ let package = Package( final String supportedPlatform = platform == SupportedPlatform.ios ? '.iOS("13.0")' : '.macOS("10.15")'; expect(project.flutterPluginSwiftPackageManifest.existsSync(), isTrue); + expect(project.relativeSwiftPackagesDirectory.childLink('valid_plugin_1'), exists); + expect( + project.relativeSwiftPackagesDirectory.childLink('valid_plugin_1').targetSync(), + validPlugin1Directory.path, + ); + expect(project.relativeSwiftPackagesDirectory.childLink('valid_plugin_2'), exists); + expect( + project.relativeSwiftPackagesDirectory.childLink('valid_plugin_2').targetSync(), + validPlugin2Directory.path, + ); expect(project.flutterPluginSwiftPackageManifest.readAsStringSync(), ''' // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. @@ -243,8 +265,8 @@ let package = Package( .library(name: "FlutterGeneratedPluginSwiftPackage", type: .static, targets: ["FlutterGeneratedPluginSwiftPackage"]) ], dependencies: [ - .package(name: "valid_plugin_1", path: "/local/path/to/plugins/valid_plugin_1"), - .package(name: "valid_plugin_2", path: "/.pub-cache/plugins/valid_plugin_2") + .package(name: "valid_plugin_1", path: "../.packages/valid_plugin_1"), + .package(name: "valid_plugin_2", path: "../.packages/valid_plugin_2") ], targets: [ .target( @@ -373,11 +395,16 @@ class FakeXcodeProject extends Fake implements IosProject { String hostAppProjectName = 'Runner'; @override - Directory get flutterPluginSwiftPackageDirectory => hostAppRoot - .childDirectory('Flutter') - .childDirectory('ephemeral') - .childDirectory('Packages') - .childDirectory('FlutterGeneratedPluginSwiftPackage'); + Directory get flutterSwiftPackagesDirectory => + hostAppRoot.childDirectory('Flutter').childDirectory('ephemeral').childDirectory('Packages'); + + @override + Directory get relativeSwiftPackagesDirectory => + flutterSwiftPackagesDirectory.childDirectory('.packages'); + + @override + Directory get flutterPluginSwiftPackageDirectory => + flutterSwiftPackagesDirectory.childDirectory('FlutterGeneratedPluginSwiftPackage'); @override File get flutterPluginSwiftPackageManifest => @@ -391,13 +418,10 @@ class FakeXcodeProject extends Fake implements IosProject { } class FakePlugin extends Fake implements Plugin { - FakePlugin({ - required this.name, - required this.platforms, - required String? pluginSwiftPackageManifestPath, - }) : _pluginSwiftPackageManifestPath = pluginSwiftPackageManifestPath; + FakePlugin({required this.name, required this.platforms, required String? pluginSwiftPackagePath}) + : _pluginSwiftPackagePath = pluginSwiftPackagePath; - final String? _pluginSwiftPackageManifestPath; + final String? _pluginSwiftPackagePath; @override final String name; @@ -405,9 +429,17 @@ class FakePlugin extends Fake implements Plugin { @override final Map platforms; + @override + String? pluginSwiftPackagePath(FileSystem fileSystem, String platform) { + return _pluginSwiftPackagePath; + } + @override String? pluginSwiftPackageManifestPath(FileSystem fileSystem, String platform) { - return _pluginSwiftPackageManifestPath; + if (_pluginSwiftPackagePath == null) { + return null; + } + return '$_pluginSwiftPackagePath/Package.swift'; } } diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index abb8eb77269a1..7ca52019acfa6 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -107,7 +107,6 @@ void main() { flutterProject ..manifest = flutterManifest ..directory = fileSystem.systemTempDirectory.childDirectory('app') - ..flutterPluginsFile = flutterProject.directory.childFile('.flutter-plugins') ..flutterPluginsDependenciesFile = flutterProject.directory.childFile( '.flutter-plugins-dependencies', ); @@ -431,7 +430,7 @@ dependencies: testUsingContext( 'Refreshing the plugin list deletes the plugin file when there were plugins but no longer are', () async { - flutterProject.flutterPluginsFile.createSync(); + flutterProject.flutterPluginsDependenciesFile.createSync(); await refreshPluginsList(flutterProject); @@ -458,7 +457,6 @@ dependencies: await refreshPluginsList(flutterProject); - expect(flutterProject.flutterPluginsFile, isNot(exists), reason: 'No longer emitted'); expect(flutterProject.flutterPluginsDependenciesFile, exists); final String pluginsFileContents = @@ -483,28 +481,6 @@ dependencies: }, ); - testUsingContext( - 'Opting in to explicit-package-dependencies omits .flutter-plugins', - () async { - createFakePlugins(fs, [ - 'plugin_d', - 'plugin_a', - '/local_plugins/plugin_c', - '/local_plugins/plugin_b', - ]); - - await refreshPluginsList(flutterProject); - - expect(flutterProject.flutterPluginsFile, isNot(exists)); - expect(flutterProject.flutterPluginsDependenciesFile, exists); - }, - overrides: { - FileSystem: () => fs, - ProcessManager: FakeProcessManager.empty, - Pub: ThrowingPub.new, - }, - ); - testUsingContext( 'Refreshing the plugin list updates .flutter-plugins-dependencies if the plugins changed', () async { @@ -2153,7 +2129,7 @@ flutter: }); group('Plugin files', () { - testWithoutContext('pluginSwiftPackageManifestPath for iOS and macOS plugins', () async { + testWithoutContext('for SwiftPM and podspec paths for iOS and macOS plugins', () async { final MemoryFileSystem fs = MemoryFileSystem.test(); final Plugin plugin = Plugin( name: 'test', @@ -2168,83 +2144,19 @@ flutter: isDirectDependency: true, isDevDependency: false, ); - + expect(plugin.pluginSwiftPackagePath(fs, IOSPlugin.kConfigKey), '/path/to/test/ios/test'); expect( - plugin.pluginSwiftPackageManifestPath(fs, IOSPlugin.kConfigKey), - '/path/to/test/ios/test/Package.swift', - ); - expect( - plugin.pluginSwiftPackageManifestPath(fs, MacOSPlugin.kConfigKey), - '/path/to/test/macos/test/Package.swift', + plugin.pluginSwiftPackagePath(fs, MacOSPlugin.kConfigKey), + '/path/to/test/macos/test', ); - }); - - testWithoutContext('pluginSwiftPackageManifestPath for darwin plugins', () async { - final MemoryFileSystem fs = MemoryFileSystem.test(); - final Plugin plugin = Plugin( - name: 'test', - path: '/path/to/test/', - defaultPackagePlatforms: const {}, - pluginDartClassPlatforms: const {}, - platforms: const { - IOSPlugin.kConfigKey: IOSPlugin( - name: 'test', - classPrefix: '', - sharedDarwinSource: true, - ), - MacOSPlugin.kConfigKey: MacOSPlugin(name: 'test', sharedDarwinSource: true), - }, - dependencies: [], - isDirectDependency: true, - isDevDependency: false, - ); - expect( plugin.pluginSwiftPackageManifestPath(fs, IOSPlugin.kConfigKey), - '/path/to/test/darwin/test/Package.swift', + '/path/to/test/ios/test/Package.swift', ); expect( plugin.pluginSwiftPackageManifestPath(fs, MacOSPlugin.kConfigKey), - '/path/to/test/darwin/test/Package.swift', - ); - }); - - testWithoutContext('pluginSwiftPackageManifestPath for non darwin plugins', () async { - final MemoryFileSystem fs = MemoryFileSystem.test(); - final Plugin plugin = Plugin( - name: 'test', - path: '/path/to/test/', - defaultPackagePlatforms: const {}, - pluginDartClassPlatforms: const {}, - platforms: const { - WindowsPlugin.kConfigKey: WindowsPlugin(name: 'test', pluginClass: ''), - }, - dependencies: [], - isDirectDependency: true, - isDevDependency: false, - ); - - expect(plugin.pluginSwiftPackageManifestPath(fs, IOSPlugin.kConfigKey), isNull); - expect(plugin.pluginSwiftPackageManifestPath(fs, MacOSPlugin.kConfigKey), isNull); - expect(plugin.pluginSwiftPackageManifestPath(fs, WindowsPlugin.kConfigKey), isNull); - }); - - testWithoutContext('pluginPodspecPath for iOS and macOS plugins', () async { - final MemoryFileSystem fs = MemoryFileSystem.test(); - final Plugin plugin = Plugin( - name: 'test', - path: '/path/to/test/', - defaultPackagePlatforms: const {}, - pluginDartClassPlatforms: const {}, - platforms: const { - IOSPlugin.kConfigKey: IOSPlugin(name: 'test', classPrefix: ''), - MacOSPlugin.kConfigKey: MacOSPlugin(name: 'test'), - }, - dependencies: [], - isDirectDependency: true, - isDevDependency: false, + '/path/to/test/macos/test/Package.swift', ); - expect( plugin.pluginPodspecPath(fs, IOSPlugin.kConfigKey), '/path/to/test/ios/test.podspec', @@ -2255,7 +2167,7 @@ flutter: ); }); - testWithoutContext('pluginPodspecPath for darwin plugins', () async { + testWithoutContext('for SwiftPM and podspec paths for darwin plugins', () async { final MemoryFileSystem fs = MemoryFileSystem.test(); final Plugin plugin = Plugin( name: 'test', @@ -2275,6 +2187,22 @@ flutter: isDevDependency: false, ); + expect( + plugin.pluginSwiftPackagePath(fs, IOSPlugin.kConfigKey), + '/path/to/test/darwin/test', + ); + expect( + plugin.pluginSwiftPackagePath(fs, MacOSPlugin.kConfigKey), + '/path/to/test/darwin/test', + ); + expect( + plugin.pluginSwiftPackageManifestPath(fs, IOSPlugin.kConfigKey), + '/path/to/test/darwin/test/Package.swift', + ); + expect( + plugin.pluginSwiftPackageManifestPath(fs, MacOSPlugin.kConfigKey), + '/path/to/test/darwin/test/Package.swift', + ); expect( plugin.pluginPodspecPath(fs, IOSPlugin.kConfigKey), '/path/to/test/darwin/test.podspec', @@ -2285,7 +2213,7 @@ flutter: ); }); - testWithoutContext('pluginPodspecPath for non darwin plugins', () async { + testWithoutContext('for SwiftPM and podspec paths for non darwin plugins', () async { final MemoryFileSystem fs = MemoryFileSystem.test(); final Plugin plugin = Plugin( name: 'test', @@ -2300,6 +2228,12 @@ flutter: isDevDependency: false, ); + expect(plugin.pluginSwiftPackagePath(fs, IOSPlugin.kConfigKey), isNull); + expect(plugin.pluginSwiftPackagePath(fs, MacOSPlugin.kConfigKey), isNull); + expect(plugin.pluginSwiftPackagePath(fs, WindowsPlugin.kConfigKey), isNull); + expect(plugin.pluginSwiftPackageManifestPath(fs, IOSPlugin.kConfigKey), isNull); + expect(plugin.pluginSwiftPackageManifestPath(fs, MacOSPlugin.kConfigKey), isNull); + expect(plugin.pluginSwiftPackageManifestPath(fs, WindowsPlugin.kConfigKey), isNull); expect(plugin.pluginPodspecPath(fs, IOSPlugin.kConfigKey), isNull); expect(plugin.pluginPodspecPath(fs, MacOSPlugin.kConfigKey), isNull); expect(plugin.pluginPodspecPath(fs, WindowsPlugin.kConfigKey), isNull); @@ -2794,7 +2728,6 @@ flutter: flutterProject ..manifest = flutterManifest - ..flutterPluginsFile = flutterProject.directory.childFile('.flutter-plugins') ..flutterPluginsDependenciesFile = flutterProject.directory.childFile( '.flutter-plugins-dependencies', ) @@ -2872,9 +2805,6 @@ class FakeFlutterProject extends Fake implements FlutterProject { @override late Directory directory; - @override - late File flutterPluginsFile; - @override late File flutterPluginsDependenciesFile; diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 08c295ed1b788..0bff26451de6c 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -35,11 +35,6 @@ import '../src/package_config.dart'; import '../src/throwing_pub.dart'; void main() { - FeatureFlags disableExplicitPackageDependencies() { - // ignore: avoid_redundant_argument_values - return TestFeatureFlags(isExplicitPackageDependenciesEnabled: false); - } - // TODO(zanderso): remove once FlutterProject is fully refactored. // this is safe since no tests have expectations on the test logger. final BufferLogger logger = BufferLogger.test(); @@ -280,33 +275,7 @@ void main() { }); testUsingContext( - '--no-explicit-package-dependencies does not determine dev dependencies', - () async { - // Create a plugin. - await aPluginProject(legacy: false); - // Create a project that depends on that plugin. - final FlutterProject project = await projectWithPluginDependency(); - // Don't bother with Android, we just want the manifest. - project.directory.childDirectory('android').deleteSync(recursive: true); - - await project.regeneratePlatformSpecificTooling(releaseMode: false); - expect( - project.flutterPluginsDependenciesFile.readAsStringSync(), - isNot(contains('"dev_dependency":true')), - ); - }, - overrides: { - FeatureFlags: disableExplicitPackageDependencies, - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), - Pub: () => const ThrowingPub(), - FlutterProjectFactory: - () => FlutterProjectFactory(logger: logger, fileSystem: globals.fs), - }, - ); - - testUsingContext( - '--explicit-package-dependencies determines dev dependencies', + 'determines dev dependencies', () async { // Create a plugin. await aPluginProject(legacy: false); @@ -331,7 +300,7 @@ void main() { ); testUsingContext( - '--explicit-package-dependencies with releaseMode: false retains dev plugins', + 'releaseMode: false retains dev plugins', () async { // Create a plugin. await aPluginProject(includeAndroidMain: true, legacy: false); @@ -354,7 +323,7 @@ void main() { ); testUsingContext( - '--explicit-package-dependencies with releaseMode: true omits dev plugins', + 'releaseMode: true omits dev plugins', () async { // Create a plugin. await aPluginProject(includeAndroidMain: true, legacy: false); 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 97859cd1536c0..d3fcf0587137d 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 @@ -735,7 +735,8 @@ name: my_app trackWidgetCreation: true, treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', - // Hot reload only supported with these flags for now. + // TODO(nshahan): Remove when hot reload can no longer be disabled. + webEnableHotReload: true, extraFrontEndOptions: kDdcLibraryBundleFlags, ), ), @@ -842,7 +843,8 @@ name: my_app trackWidgetCreation: true, treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', - // Hot reload only supported with these flags for now. + // TODO(nshahan): Remove when hot reload can no longer be disabled. + webEnableHotReload: true, extraFrontEndOptions: kDdcLibraryBundleFlags, ), ), @@ -927,7 +929,8 @@ name: my_app trackWidgetCreation: true, treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', - // Hot reload only supported with these flags for now. + // TODO(nshahan): Remove when hot reload can no longer be disabled. + webEnableHotReload: true, extraFrontEndOptions: kDdcLibraryBundleFlags, ), webUseWasm: true, @@ -996,13 +999,14 @@ name: my_app // Test one extra config where `fullRestart` is false without the DDC library // bundle format - we should do a hot restart in this case because hot reload // is not available. - for (final (List flags, bool fullRestart) in <(List, bool)>[ - (kDdcLibraryBundleFlags, true), - ([], true), - ([], false), + for (final (bool webEnableHotReload, bool fullRestart) in <(bool, bool)>[ + (true, true), + (false, true), + (false, false), ]) { testUsingContext( - 'Can hot restart after attaching with flags: $flags fullRestart: $fullRestart', + 'Can hot restart after attaching with ' + 'webEnableHotReload: $webEnableHotReload fullRestart: $fullRestart', () async { final BufferLogger logger = BufferLogger.test(); final ResidentRunner residentWebRunner = setUpResidentRunner( @@ -1016,7 +1020,8 @@ name: my_app trackWidgetCreation: true, treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', - extraFrontEndOptions: flags, + extraFrontEndOptions: webEnableHotReload ? kDdcLibraryBundleFlags : const [], + webEnableHotReload: webEnableHotReload, ), ), ); @@ -1242,8 +1247,9 @@ name: my_app }, ); + // TODO(nshahan): Delete this test case when hot reload can no longer be disabled. testUsingContext( - 'Fails non-fatally on vmservice response error for hot restart', + 'Fails non-fatally on vmservice response error for hot restart (legacy default case)', () async { final ResidentRunner residentWebRunner = setUpResidentRunner(flutterDevice); fakeVmServiceHost = FakeVmServiceHost( @@ -1261,6 +1267,8 @@ name: my_app unawaited(residentWebRunner.run(connectionInfoCompleter: connectionInfoCompleter)); await connectionInfoCompleter.future; + // Historically the .restart() would perform a hot restart even without + // passing fullRestart: true. final OperationResult result = await residentWebRunner.restart(); expect(result.code, 0); @@ -1272,8 +1280,9 @@ name: my_app }, ); + // TODO(nshahan): Delete this test case when hot reload can no longer be disabled. testUsingContext( - 'Fails fatally on Vm Service error response', + 'Fails fatally on Vm Service error response (legacy default case)', () async { final ResidentRunner residentWebRunner = setUpResidentRunner(flutterDevice); fakeVmServiceHost = FakeVmServiceHost( @@ -1303,6 +1312,94 @@ name: my_app }, ); + for (final bool webEnableHotReload in [true, false]) { + testUsingContext( + 'Fails non-fatally on vmservice response error for hot restart with webEnableHotReload: $webEnableHotReload', + () async { + final ResidentRunner residentWebRunner = setUpResidentRunner( + flutterDevice, + debuggingOptions: DebuggingOptions.enabled( + BuildInfo( + BuildMode.debug, + null, + trackWidgetCreation: true, + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + webEnableHotReload: webEnableHotReload, + extraFrontEndOptions: webEnableHotReload ? kDdcLibraryBundleFlags : [], + ), + ), + ); + fakeVmServiceHost = FakeVmServiceHost( + requests: [ + ...kAttachExpectations, + const FakeVmServiceRequest( + method: kHotRestartServiceName, + jsonResponse: {'type': 'Failed'}, + ), + ], + ); + setupMocks(); + final Completer connectionInfoCompleter = + Completer(); + unawaited(residentWebRunner.run(connectionInfoCompleter: connectionInfoCompleter)); + await connectionInfoCompleter.future; + + final OperationResult result = await residentWebRunner.restart(fullRestart: true); + + expect(result.code, 0); + }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + Pub: ThrowingPub.new, + }, + ); + + testUsingContext( + 'Fails fatally on Vm Service error response with webEnableHotReload: $webEnableHotReload', + () async { + final ResidentRunner residentWebRunner = setUpResidentRunner( + flutterDevice, + debuggingOptions: DebuggingOptions.enabled( + BuildInfo( + BuildMode.debug, + null, + trackWidgetCreation: true, + treeShakeIcons: false, + packageConfigPath: '.dart_tool/package_config.json', + webEnableHotReload: webEnableHotReload, + extraFrontEndOptions: webEnableHotReload ? kDdcLibraryBundleFlags : [], + ), + ), + ); + fakeVmServiceHost = FakeVmServiceHost( + requests: [ + ...kAttachExpectations, + FakeVmServiceRequest( + method: kHotRestartServiceName, + // Failed response, + error: FakeRPCError(code: vm_service.RPCErrorKind.kInternalError.code), + ), + ], + ); + setupMocks(); + final Completer connectionInfoCompleter = + Completer(); + unawaited(residentWebRunner.run(connectionInfoCompleter: connectionInfoCompleter)); + await connectionInfoCompleter.future; + final OperationResult result = await residentWebRunner.restart(fullRestart: true); + + expect(result.code, 1); + expect(result.message, contains(vm_service.RPCErrorKind.kInternalError.code.toString())); + }, + overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + Pub: ThrowingPub.new, + }, + ); + } testUsingContext( 'printHelp without details shows only hot restart help message', () async { @@ -1335,7 +1432,8 @@ name: my_app trackWidgetCreation: true, treeShakeIcons: false, packageConfigPath: '.dart_tool/package_config.json', - // Hot reload only supported with these flags for now. + // TODO(nshahan): Remove when hot reload can no longer be disabled. + webEnableHotReload: true, extraFrontEndOptions: kDdcLibraryBundleFlags, ), ), diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 00b603d354f2a..fbda6491f992a 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -1270,6 +1270,98 @@ flutter: ); }); + testUsingContext( + "tool exits when $kAppFlavor is already set in user's environemnt", + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run(['run', '--no-pub', '--no-hot']), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set in the environment.', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + Platform: () => FakePlatform()..environment = {kAppFlavor: 'AlreadySet'}, + }, + ); + + testUsingContext( + 'tool exits when $kAppFlavor is set in --dart-define', + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run([ + 'run', + '--dart-define=$kAppFlavor=AlreadySet', + '--no-pub', + '--no-hot', + ]), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set using --dart-define', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + }, + ); + + testUsingContext( + 'tool exits when $kAppFlavor is set in --dart-define-from-file', + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run([ + 'run', + '--dart-define-from-file=config.json', + '--no-pub', + '--no-hot', + ]), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set using --dart-define', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('config.json') + ..createSync() + ..writeAsStringSync('{"$kAppFlavor": "AlreadySet"}'); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + }, + ); + group('Flutter version', () { for (final String dartDefine in FlutterCommand.flutterVersionDartDefines) { testUsingContext( diff --git a/packages/flutter_tools/test/general.shard/unified_analytics_test.dart b/packages/flutter_tools/test/general.shard/unified_analytics_test.dart index 0f7195a42a27e..0362b152cc9be 100644 --- a/packages/flutter_tools/test/general.shard/unified_analytics_test.dart +++ b/packages/flutter_tools/test/general.shard/unified_analytics_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/reporting/unified_analytics.dart'; import 'package:unified_analytics/unified_analytics.dart'; import '../src/common.dart'; +import '../src/context.dart'; import '../src/fakes.dart'; void main() { @@ -30,12 +31,12 @@ void main() { }); group('Unit testing util:', () { - test('getEnabledFeatures is null', () { + testUsingContext('getEnabledFeatures is null', () { final String? enabledFeatures = getEnabledFeatures(config); expect(enabledFeatures, isNull); }); - testWithoutContext('getEnabledFeatures not null', () { + testUsingContext('getEnabledFeatures not null', () { config.setValue('cli-animations', true); final String? enabledFeatures = getEnabledFeatures(config); diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index 6b735b15957ec..4a807f83f4467 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -2,117 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:file/memory.dart'; -import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/commands/update_packages.dart'; import 'package:flutter_tools/src/update_packages_pins.dart'; import '../src/common.dart'; -// An example pubspec.yaml from flutter, not necessary for it to be up to date. -const String kFlutterPubspecYaml = r''' -name: flutter -description: A framework for writing Flutter applications -homepage: http://flutter.dev - -environment: - sdk: ^3.7.0-0 - -dependencies: - # To update these, use "flutter update-packages --force-upgrade". - collection: 1.14.11 - meta: 1.1.8 - macros: 0.0.1 - typed_data: 1.1.6 - vector_math: 2.0.8 - - sky_engine: - sdk: flutter - - gallery: - git: - url: https://github.com/flutter/gallery.git - ref: d00362e6bdd0f9b30bba337c358b9e4a6e4ca950 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_goldens: - sdk: flutter - - archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - -# PUBSPEC CHECKSUM: 1437 -'''; - -const String kExtraPubspecYaml = r''' -name: nodeps -description: A dummy pubspec with no dependencies -homepage: http://flutter.dev - -environment: - sdk: ^3.7.0-0 -'''; - -const String kInvalidGitPubspec = ''' -name: flutter -description: A framework for writing Flutter applications -homepage: http://flutter.dev - -environment: - sdk: ^3.7.0-0 - -dependencies: - # To update these, use "flutter update-packages --force-upgrade". - collection: 1.14.11 - meta: 1.1.8 - typed_data: 1.1.6 - vector_math: 2.0.8 - - sky_engine: - sdk: flutter - - gallery: - git: -'''; - -const String kVersionJson = ''' -{ - "frameworkVersion": "1.2.3", - "channel": "[user-branch]", - "repositoryUrl": "git@github.com:flutter/flutter.git", - "frameworkRevision": "1234567812345678123456781234567812345678", - "frameworkCommitDate": "2024-02-06 22:26:52 +0100", - "engineRevision": "abcdef01abcdef01abcdef01abcdef01abcdef01", - "dartSdkVersion": "1.2.3", - "devToolsVersion": "1.2.3", - "flutterVersion": "1.2.3" -} -'''; - void main() { - late FileSystem fileSystem; - late Directory flutterSdk; - late Directory flutter; - - setUp(() { - fileSystem = MemoryFileSystem.test(); - // Setup simplified Flutter SDK. - flutterSdk = fileSystem.directory('flutter')..createSync(); - // Create version file - flutterSdk.childFile('version').writeAsStringSync('1.2.3'); - // Create version JSON file - flutterSdk.childDirectory('bin').childDirectory('cache').childFile('flutter.version.json') - ..createSync(recursive: true) - ..writeAsStringSync(kVersionJson); - // Create a pubspec file - flutter = flutterSdk.childDirectory('packages').childDirectory('flutter') - ..createSync(recursive: true); - flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml); - }); - testWithoutContext('kManuallyPinnedDependencies pins are actually pins', () { expect( kManuallyPinnedDependencies.values, @@ -120,145 +14,4 @@ void main() { reason: 'Version pins in kManuallyPinnedDependencies must be specific pins, not ranges.', ); }); - - testWithoutContext('createTemporaryFlutterSdk creates an unpinned flutter SDK', () { - // A stray extra package should not cause a crash. - final Directory extra = flutterSdk.childDirectory('packages').childDirectory('extra') - ..createSync(recursive: true); - extra.childFile('pubspec.yaml').writeAsStringSync(kExtraPubspecYaml); - - // Create already parsed pubspecs. - final PubspecYaml flutterPubspec = PubspecYaml(flutter); - - final PubspecDependency gitDependency = flutterPubspec.dependencies.firstWhere( - (PubspecDependency dep) => dep.kind == DependencyKind.git, - ); - expect(gitDependency.lockLine, ''' - git: - url: https://github.com/flutter/gallery.git - ref: d00362e6bdd0f9b30bba337c358b9e4a6e4ca950 -'''); - final BufferLogger bufferLogger = BufferLogger.test(); - final Directory result = createTemporaryFlutterSdk( - bufferLogger, - fileSystem, - flutterSdk, - [flutterPubspec], - fileSystem.systemTempDirectory, - ); - - expect(result, exists); - - // We get a warning about the unexpected package. - expect( - bufferLogger.warningText, - contains("Unexpected package 'extra' found in packages directory"), - ); - - // The version file exists. - expect(result.childFile('version'), exists); - expect(result.childFile('version').readAsStringSync(), '1.2.3'); - expect( - fileSystem.file(fileSystem.path.join(result.path, 'bin', 'cache', 'flutter.version.json')), - exists, - ); - - // The sky_engine package exists - expect(fileSystem.directory('${result.path}/bin/cache/pkg/sky_engine'), exists); - - // The flutter pubspec exists - final File pubspecFile = fileSystem.file('${result.path}/packages/flutter/pubspec.yaml'); - expect(pubspecFile, exists); - - // The flutter pubspec contains `any` dependencies. - final PubspecYaml outputPubspec = PubspecYaml(pubspecFile.parent); - expect(outputPubspec.name, 'flutter'); - expect(outputPubspec.dependencies.first.name, 'collection'); - expect(outputPubspec.dependencies.first.version, 'any'); - }); - - testWithoutContext('Throws a StateError on a malformed git: reference', () { - // Create an invalid pubspec file. - flutter.childFile('pubspec.yaml').writeAsStringSync(kInvalidGitPubspec); - - expect(() => PubspecYaml(flutter), throwsStateError); - }); - - testWithoutContext('PubspecYaml Loads dependencies', () async { - final PubspecYaml pubspecYaml = PubspecYaml(flutter); - expect( - pubspecYaml.allDependencies - .map( - (PubspecDependency dependency) => '${dependency.name}: ${dependency.version}', - ) - .toSet(), - equals({ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'macros: 0.0.1', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ', - 'flutter_test: ', - 'flutter_goldens: ', - 'archive: 2.0.11', - }), - ); - expect( - pubspecYaml.allExplicitDependencies - .map( - (PubspecDependency dependency) => '${dependency.name}: ${dependency.version}', - ) - .toSet(), - equals({ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'macros: 0.0.1', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ', - 'flutter_test: ', - 'flutter_goldens: ', - }), - ); - expect( - pubspecYaml.dependencies - .map( - (PubspecDependency dependency) => '${dependency.name}: ${dependency.version}', - ) - .toSet(), - equals({ - 'collection: 1.14.11', - 'meta: 1.1.8', - 'macros: 0.0.1', - 'typed_data: 1.1.6', - 'vector_math: 2.0.8', - 'sky_engine: ', - 'gallery: ', - }), - ); - }); - - testWithoutContext('PubspecYaml apply skips explicitly excluded packages', () async { - final PubspecYaml flutterPubspec = PubspecYaml(flutter); - final PubDependencyTree flutterTree = PubDependencyTree(); - final List depsLines = [ - // Have to add these first so that flutterTree.fill ignores the one in - // the pubspec. - '- macros 0.0.1 [_macros]', - '- _macros 0.0.1', - for (final PubspecDependency dependency in flutterPubspec.allDependencies) - '- ${dependency.name} ${dependency.version}', - ]; - - final Set dependencies = - flutterPubspec.allDependencies.map((PubspecDependency dep) => dep.name).toSet(); - depsLines.add('- flutter 1.0.0 [${dependencies.join(' ')}}]'); - depsLines.forEach(flutterTree.fill); - flutterPubspec.apply(flutterTree, {}); - final String contents = flutter.childFile('pubspec.yaml').readAsStringSync(); - expect(contents, isNot(contains('_macros: 0.0.1'))); - }); } diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index ecd4221faf289..8f0c339859f74 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'package:file/file.dart'; import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/process.dart'; @@ -60,13 +61,19 @@ void main() { const String flutterRoot = '/path/to/flutter'; setUpAll(() { - fs = MemoryFileSystem.test(); Cache.disableLocking(); VersionFreshnessValidator.timeToPauseToLetUserReadTheMessage = Duration.zero; }); + setUp(() { + fs = MemoryFileSystem.test(); + fs.directory(flutterRoot).createSync(recursive: true); + FlutterVersion.getVersionFile(fs, flutterRoot).createSync(recursive: true); + fs.file(fs.path.join(flutterRoot, 'version')).createSync(recursive: true); + }); + testUsingContext( - 'prints nothing when Flutter installation looks fresh', + 'prints nothing when Flutter installation looks fresh $channel', () async { const String flutterUpstreamUrl = 'https://github.com/flutter/flutter.git'; processManager.addCommands([ @@ -227,6 +234,199 @@ void main() { overrides: {ProcessManager: () => processManager, Cache: () => cache}, ); + // Regression test for https://github.com/flutter/flutter/issues/142521 + testUsingContext( + 'does not remove version files when fetching tags', + () async { + const String flutterUpstreamUrl = 'https://github.com/flutter/flutter.git'; + processManager.addCommands([ + const FakeCommand( + command: [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + '-n', + '1', + '--pretty=format:%H', + ], + stdout: '1234abcd', + ), + const FakeCommand(command: ['git', 'symbolic-ref', '--short', 'HEAD']), + const FakeCommand( + command: [ + 'git', + 'fetch', + 'https://github.com/flutter/flutter.git', + '--tags', + '-f', + ], + ), + const FakeCommand(command: ['git', 'tag', '--points-at', '1234abcd']), + const FakeCommand( + command: [ + 'git', + 'describe', + '--match', + '*.*.*', + '--long', + '--tags', + '1234abcd', + ], + stdout: '0.1.2-3-1234abcd', + ), + FakeCommand( + command: const ['git', 'symbolic-ref', '--short', 'HEAD'], + stdout: channel, + ), + FakeCommand( + command: const [ + 'git', + 'rev-parse', + '--abbrev-ref', + '--symbolic', + '@{upstream}', + ], + stdout: 'origin/$channel', + ), + const FakeCommand( + command: ['git', 'ls-remote', '--get-url', 'origin'], + stdout: flutterUpstreamUrl, + ), + FakeCommand( + command: const [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + 'HEAD', + '-n', + '1', + '--pretty=format:%ad', + '--date=iso', + ], + stdout: getChannelUpToDateVersion().toString(), + ), + FakeCommand( + command: const [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + 'abcdefg', + '-n', + '1', + '--pretty=format:%ad', + '--date=iso', + ], + stdout: getChannelUpToDateVersion().toString(), + ), + FakeCommand( + command: const [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + 'HEAD', + '-n', + '1', + '--pretty=format:%ad', + '--date=iso', + ], + stdout: getChannelUpToDateVersion().toString(), + ), + const FakeCommand(command: ['git', 'fetch', '--tags']), + FakeCommand( + command: const [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + '@{upstream}', + '-n', + '1', + '--pretty=format:%ad', + '--date=iso', + ], + stdout: getChannelUpToDateVersion().toString(), + ), + const FakeCommand( + command: [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + '-n', + '1', + '--pretty=format:%ar', + ], + stdout: '1 second ago', + ), + FakeCommand( + command: const [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + 'HEAD', + '-n', + '1', + '--pretty=format:%ad', + '--date=iso', + ], + stdout: getChannelUpToDateVersion().toString(), + ), + const FakeCommand( + command: [ + 'git', + '-c', + 'log.showSignature=false', + 'log', + '-n', + '1', + '--pretty=format:%ar', + 'abcdefg', + ], + stdout: '2 seconds ago', + ), + ]); + + final FlutterVersion flutterVersion = FlutterVersion( + clock: _testClock, + fs: fs, + flutterRoot: flutterRoot, + fetchTags: true, + ); + await flutterVersion.checkFlutterVersionFreshness(); + + // Verify the version files exist and have been repopulated after the fetch. + expect(FlutterVersion.getVersionFile(fs, flutterRoot), exists); // flutter.version.json + expect(fs.file(fs.path.join(flutterRoot, 'version')), exists); // legacy + + expect(flutterVersion.channel, channel); + expect(flutterVersion.repositoryUrl, flutterUpstreamUrl); + expect(flutterVersion.frameworkRevision, '1234abcd'); + expect(flutterVersion.frameworkRevisionShort, '1234abcd'); + expect(flutterVersion.frameworkVersion, '0.0.0-unknown'); + expect( + flutterVersion.toString(), + 'Flutter • channel $channel • $flutterUpstreamUrl\n' + 'Framework • revision 1234abcd (1 second ago) • ${getChannelUpToDateVersion()}\n' + 'Engine • revision abcdefg (2 seconds ago) • ${getChannelUpToDateVersion()}\n' + 'Tools • Dart 2.12.0 • DevTools 2.8.0', + ); + expect(flutterVersion.frameworkAge, '1 second ago'); + expect(flutterVersion.getVersionString(), '$channel/1234abcd'); + expect(flutterVersion.getBranchName(), channel); + expect(flutterVersion.getVersionString(redactUnknownBranches: true), '$channel/1234abcd'); + expect(flutterVersion.getBranchName(redactUnknownBranches: true), channel); + + expect(testLogger.statusText, isEmpty); + expect(processManager, hasNoRemainingExpectations); + }, + overrides: {ProcessManager: () => processManager, Cache: () => cache}, + ); + testUsingContext( 'does not crash when git log outputs malformed output', () async { diff --git a/packages/flutter_tools/test/general.shard/vscode/vscode_test.dart b/packages/flutter_tools/test/general.shard/vscode/vscode_test.dart index 8fc2891fd4ae1..5385cc4d5a204 100644 --- a/packages/flutter_tools/test/general.shard/vscode/vscode_test.dart +++ b/packages/flutter_tools/test/general.shard/vscode/vscode_test.dart @@ -5,6 +5,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/vscode/vscode.dart'; import '../../src/common.dart'; @@ -55,11 +56,35 @@ void main() { ..createSync(recursive: true) ..writeAsStringSync('{'); - final VsCode vsCode = VsCode.fromDirectory('', '', fileSystem: fileSystem); + final VsCode vsCode = VsCode.fromDirectory( + '', + '', + fileSystem: fileSystem, + platform: const LocalPlatform(), + ); expect(vsCode.version, null); }); + testWithoutContext('VsCode.fromDirectory finds packages.json on Linux', () { + // Regression test for https://github.com/flutter/flutter/issues/169812 + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + // Installations on Linux appear to use $VSCODE_INSTALL/resources/app/package.json rather than + // $VSCODE_INSTALL/Resources/app/package.json. + fileSystem.file(fileSystem.path.join('', 'resources', 'app', 'package.json')) + ..createSync(recursive: true) + ..writeAsStringSync('{"version":"1.2.3"}'); + + final VsCode vsCode = VsCode.fromDirectory( + '', + '', + fileSystem: fileSystem, + platform: FakePlatform(), + ); + + expect(vsCode.version, Version(1, 2, 3)); + }); + testWithoutContext('can locate VS Code installed via Snap', () { final FileSystem fileSystem = MemoryFileSystem.test(); const String home = '/home/me'; diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart index 93a998b73a500..1ff451367ffdf 100644 --- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart @@ -53,7 +53,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', '-dTargetDeviceOSVersion=', 'debug_ios_bundle_flutter_assets', ], @@ -104,6 +103,7 @@ void main() { 'CONFIGURATION': buildMode, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -128,7 +128,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], if (platform == TargetPlatform.macos) ...[ '--build-inputs=/Flutter/ephemeral/FlutterInputs.xcfilelist', @@ -169,7 +168,6 @@ void main() { const String treeShake = 'true'; const String srcRoot = '/path/to/project'; const String iOSVersion = '18.3.1'; - const String devDependenciesEnabled = 'true'; final TestContext context = TestContext( ['build', platformName], { @@ -193,7 +191,7 @@ void main() { 'TREE_SHAKE_ICONS': treeShake, 'SRCROOT': srcRoot, 'TARGET_DEVICE_OS_VERSION': iOSVersion, - 'FLUTTER_DEV_DEPENDENCIES_ENABLED': devDependenciesEnabled, + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -219,7 +217,6 @@ void main() { '--DartDefines=$dartDefines', '--ExtraFrontEndOptions=$extraFrontEndOptions', '-dSrcRoot=$srcRoot', - '-dDevDependenciesEnabled=$devDependenciesEnabled', if (platform == TargetPlatform.ios) ...[ '-dTargetDeviceOSVersion=$iOSVersion', '-dCodesignIdentity=$expandedCodeSignIdentity', @@ -237,6 +234,137 @@ void main() { expect(context.stdout, contains('built and packaged successfully.')); expect(context.stderr, isEmpty); }); + + test( + 'exits with useful error message when missing FLUTTER_CLI_BUILD_MODE during archive', + () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'install', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + }, + commands: [], + fileSystem: fileSystem, + ); + expect(() => context.run(), throwsException); + expect( + context.stderr, + contains( + 'error: Your Flutter build settings are outdated. ' + 'Please run "flutter build ${platform.name} --config-only --release" ' + 'in your Flutter project and try again.', + ), + ); + }, + ); + + test('exits with useful error message when build mode mismatches during archive', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'install', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, + commands: [], + fileSystem: fileSystem, + ); + expect(() => context.run(), throwsException); + expect( + context.stderr, + contains( + 'error: Your Flutter project is currently configured for debug mode. ' + 'Please run `flutter build ${platform.name} --config-only --release` ' + 'in your Flutter project to update your settings.', + ), + ); + }); + + test('prints useful warning message when missing FLUTTER_CLI_BUILD_MODE', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'build', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + }, + commands: [], + fileSystem: fileSystem, + fakeProcessManager: FakeProcessManager.any(), + ); + context.run(); + expect( + context.stderr, + contains( + 'warning: Your Flutter build settings are outdated. ' + 'Please run "flutter build ${platform.name} --config-only --release" ' + 'in your Flutter project and try again.', + ), + ); + }); + + test('prints useful warning message when build mode mismatches', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'debug', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, + commands: [], + fileSystem: fileSystem, + fakeProcessManager: FakeProcessManager.any(), + ); + context.run(); + expect( + context.stderr, + contains( + 'warning: Your Flutter project is currently configured for debug mode. ' + 'Please run `flutter build ${platform.name} --config-only --release` ' + 'in your Flutter project to update your settings.', + ), + ); + }); }); } @@ -281,6 +409,7 @@ void main() { 'BUILT_PRODUCTS_DIR': buildDir.path, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -332,6 +461,7 @@ void main() { 'CONFIGURATION': buildMode, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -356,7 +486,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -389,7 +518,6 @@ void main() { const String treeShake = 'true'; const String srcRoot = '/path/to/project'; const String iOSVersion = '18.3.1'; - const String devDependenciesEnabled = 'true'; final TestContext context = TestContext( ['prepare', platformName], { @@ -413,7 +541,7 @@ void main() { 'TREE_SHAKE_ICONS': treeShake, 'SRCROOT': srcRoot, 'TARGET_DEVICE_OS_VERSION': iOSVersion, - 'FLUTTER_DEV_DEPENDENCIES_ENABLED': devDependenciesEnabled, + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -439,7 +567,6 @@ void main() { '--DartDefines=$dartDefines', '--ExtraFrontEndOptions=$extraFrontEndOptions', '-dSrcRoot=$srcRoot', - '-dDevDependenciesEnabled=$devDependenciesEnabled', if (platform == TargetPlatform.ios) ...[ '-dTargetDeviceOSVersion=$iOSVersion', '-dCodesignIdentity=$expandedCodeSignIdentity', @@ -472,6 +599,7 @@ void main() { 'ARCHS': 'arm64 x86_64', 'ONLY_ACTIVE_ARCH': 'YES', 'NATIVE_ARCH': 'arm64e', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -496,7 +624,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -527,6 +654,7 @@ void main() { 'ARCHS': 'arm64', 'ONLY_ACTIVE_ARCH': 'YES', 'NATIVE_ARCH': 'x86_64', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -551,7 +679,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -581,6 +708,7 @@ void main() { 'INFOPLIST_PATH': 'Info.plist', 'ARCHS': 'arm64 x86_64', 'NATIVE_ARCH': 'arm64e', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -605,7 +733,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -902,7 +1029,8 @@ class TestContext extends Context { required this.fileSystem, required List commands, File? scriptOutputStreamFile, - }) : processManager = FakeProcessManager.list(commands), + FakeProcessManager? fakeProcessManager, + }) : processManager = fakeProcessManager ?? FakeProcessManager.list(commands), super( arguments: arguments, environment: environment, diff --git a/packages/flutter_tools/test/general.shard/xcode_project_test.dart b/packages/flutter_tools/test/general.shard/xcode_project_test.dart index 65f1cf8af0f98..fe5241774744c 100644 --- a/packages/flutter_tools/test/general.shard/xcode_project_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_project_test.dart @@ -51,6 +51,21 @@ void main() { expect(project.ephemeralDirectory.path, 'app_name/.ios/Flutter/ephemeral'); }); + testWithoutContext('flutterSwiftPackagesDirectory', () { + final MemoryFileSystem fs = MemoryFileSystem.test(); + final IosProject project = IosProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); + expect(project.flutterSwiftPackagesDirectory.path, 'app_name/ios/Flutter/ephemeral/Packages'); + }); + + testWithoutContext('relativeSwiftPackagesDirectory', () { + final MemoryFileSystem fs = MemoryFileSystem.test(); + final IosProject project = IosProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); + expect( + project.relativeSwiftPackagesDirectory.path, + 'app_name/ios/Flutter/ephemeral/Packages/.packages', + ); + }); + testWithoutContext('flutterPluginSwiftPackageDirectory', () { final MemoryFileSystem fs = MemoryFileSystem.test(); final IosProject project = IosProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); @@ -440,6 +455,24 @@ void main() { expect(project.ephemeralDirectory.path, 'app_name/macos/Flutter/ephemeral'); }); + testWithoutContext('flutterSwiftPackagesDirectory', () { + final MemoryFileSystem fs = MemoryFileSystem.test(); + final MacOSProject project = MacOSProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); + expect( + project.flutterSwiftPackagesDirectory.path, + 'app_name/macos/Flutter/ephemeral/Packages', + ); + }); + + testWithoutContext('relativeSwiftPackagesDirectory', () { + final MemoryFileSystem fs = MemoryFileSystem.test(); + final MacOSProject project = MacOSProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); + expect( + project.relativeSwiftPackagesDirectory.path, + 'app_name/macos/Flutter/ephemeral/Packages/.packages', + ); + }); + testWithoutContext('flutterPluginSwiftPackageDirectory', () { final MemoryFileSystem fs = MemoryFileSystem.test(); final MacOSProject project = MacOSProject.fromFlutter(FakeFlutterProject(fileSystem: fs)); 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 9c26e18a0f5d7..7b6b6400fc6db 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -9,6 +9,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/features.dart'; import '../src/common.dart'; +import '../src/context.dart'; import 'test_utils.dart'; // This test file does not use [getLocalEngineArguments] because it is testing @@ -58,7 +59,7 @@ void main() { expect(result.stdout, contains('Shutdown hooks complete')); }); - testWithoutContext('flutter config --list contains all features', () async { + testUsingContext('flutter config --list contains all features', () async { final ProcessResult result = await processManager.run([flutterBin, 'config', '--list']); // contains all of the experiments in features.dart diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart index c85946ee8d6fd..f360a7462a6ab 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart @@ -290,6 +290,7 @@ Exception: c The relevant error-causing widget was: App App:${Uri.file(project.dir.path)}/lib/main.dart:1:1 + ^ source: ${project.dir.path.split('.').last}${fileSystem.path.separator}lib${fileSystem.path.separator}main.dart When the exception was thrown, this was the stack: #0 c (package:test/main.dart:1:1) diff --git a/packages/flutter_tools/test/integration.shard/default_flavor_test.dart b/packages/flutter_tools/test/integration.shard/default_flavor_test.dart new file mode 100644 index 0000000000000..f84008a05d9c7 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/default_flavor_test.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. + +@Tags(['flutter-test-driver']) +library; + +import 'package:flutter_tools/src/base/file_system.dart'; + +import '../src/common.dart'; +import 'test_data/project.dart'; +import 'test_driver.dart'; +import 'test_utils.dart'; + +void main() { + final Project project = _DefaultFlavorProject(); + late Directory tempDir; + late FlutterTestTestDriver flutter; + + setUp(() async { + tempDir = createResolvedTempDirectorySync('default_flavor_test.'); + await project.setUpIn(tempDir); + flutter = FlutterTestTestDriver(tempDir); + }); + + tearDown(() async { + tryToDelete(tempDir); + }); + + testWithoutContext('Reads "default-flavor" in "flutter test"', () async { + await flutter.test(); + + // Without an assertion, this test always passes. + final int? exitCode = await flutter.done; + expect(exitCode, 0, reason: 'flutter test failed with exit code $exitCode'); + }); +} + +final class _DefaultFlavorProject extends Project { + @override + final String main = r''' + // Irrelevant to this test. + void main() {} + '''; + + @override + final String pubspec = r''' + name: test + environment: + sdk: ^3.7.0-0 + + flutter: + default-flavor: dev + + dependencies: + flutter: + sdk: flutter + dev_dependencies: + flutter_test: + sdk: flutter + '''; + + @override + final String test = r''' + import 'package:flutter/services.dart'; + import 'package:flutter_test/flutter_test.dart'; + + void main() { + test('receives default-flavor with flutter test', () async { + expect(appFlavor, 'dev'); + }); + } + '''; +} diff --git a/packages/flutter_tools/test/integration.shard/isolated/native_assets_agp_version_test.dart b/packages/flutter_tools/test/integration.shard/isolated/native_assets_agp_version_test.dart index c1b55db66a183..8fc8688319e45 100644 --- a/packages/flutter_tools/test/integration.shard/isolated/native_assets_agp_version_test.dart +++ b/packages/flutter_tools/test/integration.shard/isolated/native_assets_agp_version_test.dart @@ -127,9 +127,8 @@ void main() { expect(nativeAssetsDir, exists); // We expect one subdirectory for each Android architecture. - expect(nativeAssetsDir.listSync().length, 4); + expect(nativeAssetsDir.listSync().length, 3); expect(nativeAssetsDir..childDirectory('armeabi-v7a'), exists); - expect(nativeAssetsDir..childDirectory('x86'), exists); expect(nativeAssetsDir..childDirectory('arm64-v8a'), exists); expect(nativeAssetsDir..childDirectory('x86_64'), exists); }); diff --git a/packages/flutter_tools/test/integration.shard/swift_package_manager_test.dart b/packages/flutter_tools/test/integration.shard/swift_package_manager_test.dart index 45ba3b1453d83..c9a77ae374541 100644 --- a/packages/flutter_tools/test/integration.shard/swift_package_manager_test.dart +++ b/packages/flutter_tools/test/integration.shard/swift_package_manager_test.dart @@ -101,6 +101,71 @@ void main() { flutterBin, workingDirectoryPath, ); + + // Create a SwiftPM plugin that depends on native code from another SwiftPM plugin + final SwiftPackageManagerPlugin createdSwiftPMPlugin = + await SwiftPackageManagerUtils.createPlugin( + flutterBin, + workingDirectoryPath, + platform: platformName, + iosLanguage: iosLanguage, + usesSwiftPackageManager: true, + ); + final File swiftPMPluginPackageManifest = fileSystem + .directory(createdSwiftPMPlugin.pluginPath) + .childDirectory(platformName) + .childDirectory(createdSwiftPMPlugin.pluginName) + .childFile('Package.swift'); + final String manifestContents = swiftPMPluginPackageManifest.readAsStringSync(); + swiftPMPluginPackageManifest.writeAsStringSync( + manifestContents + .replaceFirst( + 'dependencies: []', + 'dependencies: [.package(name: "${integrationTestPlugin.pluginName}", path: "../${integrationTestPlugin.pluginName}")]', + ) + .replaceFirst( + 'dependencies: []', + 'dependencies: [.product(name: "${integrationTestPlugin.pluginName.replaceAll('_', '-')}", package: "${integrationTestPlugin.pluginName}")]', + ), + ); + final File swiftPMPluginPodspec = fileSystem + .directory(createdSwiftPMPlugin.pluginPath) + .childDirectory(platformName) + .childFile('${createdSwiftPMPlugin.pluginName}.podspec'); + final String podspecContents = swiftPMPluginPodspec.readAsStringSync(); + swiftPMPluginPodspec.writeAsStringSync( + podspecContents.replaceFirst( + '\nend', + "\n s.dependency '${integrationTestPlugin.pluginName}'\n\nend", + ), + ); + final String pluginClassFileName = + iosLanguage == 'swift' + ? '${createdSwiftPMPlugin.className}.swift' + : '${createdSwiftPMPlugin.className}.m'; + final String pluginClassFileImport = + iosLanguage == 'swift' + ? 'import ${integrationTestPlugin.pluginName}' + : '@import ${integrationTestPlugin.pluginName};'; + final File pluginClassFile = fileSystem + .directory(createdSwiftPMPlugin.pluginPath) + .childDirectory(platformName) + .childDirectory(createdSwiftPMPlugin.pluginName) + .childDirectory('Sources') + .childDirectory(createdSwiftPMPlugin.pluginName) + .childFile(pluginClassFileName); + final String pluginClassFileContent = pluginClassFile.readAsStringSync(); + pluginClassFile.writeAsStringSync('$pluginClassFileImport\n$pluginClassFileContent'); + SwiftPackageManagerUtils.addDependency( + appDirectoryPath: createdSwiftPMPlugin.pluginPath, + plugin: integrationTestPlugin, + ); + + SwiftPackageManagerUtils.addDependency( + appDirectoryPath: appDirectoryPath, + plugin: createdSwiftPMPlugin, + ); + await SwiftPackageManagerUtils.buildApp( flutterBin, appDirectoryPath, @@ -731,9 +796,9 @@ void main() { expect(generatedManifestFile, exists); String generatedManifest = generatedManifestFile.readAsStringSync(); - final String generatedSwiftDependency = ''' + const String generatedSwiftDependency = ''' dependencies: [ - .package(name: "integration_test", path: "${integrationTestPlugin.swiftPackagePlatformPath}") + .package(name: "integration_test", path: "../.packages/integration_test") ], '''; @@ -828,9 +893,9 @@ void main() { String xcodeProject = xcodeProjectFile.readAsStringSync(); String generatedManifest = generatedManifestFile.readAsStringSync(); - final String generatedSwiftDependency = ''' + const String generatedSwiftDependency = ''' dependencies: [ - .package(name: "integration_test", path: "${integrationTestPlugin.swiftPackagePlatformPath}") + .package(name: "integration_test", path: "../.packages/integration_test") ], '''; diff --git a/packages/flutter_tools/test/integration.shard/swift_package_manager_utils.dart b/packages/flutter_tools/test/integration.shard/swift_package_manager_utils.dart index 365558f54ec7b..515b262b1a78f 100644 --- a/packages/flutter_tools/test/integration.shard/swift_package_manager_utils.dart +++ b/packages/flutter_tools/test/integration.shard/swift_package_manager_utils.dart @@ -211,9 +211,15 @@ class SwiftPackageManagerUtils { pluginName: pluginName, pluginPath: pluginDirectory.path, platform: platform, + className: + '${_capitalize(platform)}${_capitalize(iosLanguage)}${_capitalize(dependencyManager)}Plugin', ); } + static String _capitalize(String str) { + return str[0].toUpperCase() + str.substring(1); + } + static void addDependency({ required SwiftPackageManagerPlugin plugin, required String appDirectoryPath, @@ -269,6 +275,7 @@ class SwiftPackageManagerUtils { 'integration_test', 'integration_test_macos', ), + className: 'IntegrationTestPlugin', ); } @@ -295,7 +302,7 @@ class SwiftPackageManagerUtils { if (swiftPackageMangerEnabled) { expectedLines.addAll([ RegExp( - '${swiftPackagePlugin.pluginName}: [/private]*${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local', + '${swiftPackagePlugin.pluginName}: [/private]*$appPlatformDirectoryPath/Flutter/ephemeral/Packages/.packages/${swiftPackagePlugin.pluginName} @ local', ), "➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'", ]); @@ -335,6 +342,8 @@ class SwiftPackageManagerUtils { bool migrated = false, }) { final String frameworkName = platform == 'ios' ? 'Flutter' : 'FlutterMacOS'; + final String appPlatformDirectoryPath = fileSystem.path.join(appDirectoryPath, platform); + final List unexpectedLines = []; if (cocoaPodsPlugin == null && !migrated) { unexpectedLines.addAll([ @@ -351,7 +360,7 @@ class SwiftPackageManagerUtils { ]); } else { unexpectedLines.addAll([ - '${swiftPackagePlugin.pluginName}: ${swiftPackagePlugin.pluginPath}/$platform/${swiftPackagePlugin.pluginName} @ local', + '${swiftPackagePlugin.pluginName}: $appPlatformDirectoryPath/Flutter/ephemeral/Packages/.packages/${swiftPackagePlugin.pluginName} @ local', "➜ Explicit dependency on target '${swiftPackagePlugin.pluginName}' in project '${swiftPackagePlugin.pluginName}'", ]); } @@ -368,11 +377,13 @@ class SwiftPackageManagerPlugin { required this.pluginName, required this.pluginPath, required this.platform, + required this.className, }); final String pluginName; final String pluginPath; final String platform; + final String className; String get exampleAppPath => fileSystem.path.join(pluginPath, 'example'); String get exampleAppPlatformPath => fileSystem.path.join(exampleAppPath, platform); String get swiftPackagePlatformPath => fileSystem.path.join(pluginPath, platform, pluginName); diff --git a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart index 1043e12a0e146..dbc02f8f82efb 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart @@ -11,11 +11,7 @@ class GenL10nProject extends Project { GenL10nProject({required this.useNamedParameters}); @override - Future setUpIn( - Directory dir, { - bool useDeferredLoading = false, - bool useSyntheticPackage = false, - }) { + Future setUpIn(Directory dir, {bool useDeferredLoading = false}) { this.dir = dir; writeFile(fileSystem.path.join(dir.path, 'lib', 'l10n', 'app_en.arb'), appEn); writeFile(fileSystem.path.join(dir.path, 'lib', 'l10n', 'app_en_CA.arb'), appEnCa); @@ -28,11 +24,7 @@ class GenL10nProject extends Project { writeFile(fileSystem.path.join(dir.path, 'lib', 'l10n', 'app_zh_Hant_TW.arb'), appZhHantTw); writeFile( fileSystem.path.join(dir.path, 'l10n.yaml'), - l10nYaml( - useDeferredLoading: useDeferredLoading, - useSyntheticPackage: useSyntheticPackage, - useNamedParameters: useNamedParameters, - ), + l10nYaml(useDeferredLoading: useDeferredLoading, useNamedParameters: useNamedParameters), ); return super.setUpIn(dir); } @@ -1092,21 +1084,13 @@ void main() { ); }'''; - String l10nYaml({ - required bool useDeferredLoading, - required bool useSyntheticPackage, - required bool useNamedParameters, - }) { + String l10nYaml({required bool useDeferredLoading, required bool useNamedParameters}) { String l10nYamlString = ''; if (useDeferredLoading) { l10nYamlString += 'use-deferred-loading: true\n'; } - if (!useSyntheticPackage) { - l10nYamlString += 'synthetic-package: false\n'; - } - if (useNamedParameters) { l10nYamlString += 'use-named-parameters: true\n'; } diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_errors_common.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_errors_common.dart index 0c8b9386de6b5..e8687b2f7d45a 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_errors_common.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_errors_common.dart @@ -14,7 +14,6 @@ import 'hot_reload_const_project.dart'; void testAll({ bool chrome = false, List additionalCommandArgs = const [], - String constClassFieldRemovalErrorMessage = 'Try performing a hot restart instead.', Object? skip = false, }) { group('chrome: $chrome' @@ -35,35 +34,28 @@ void testAll({ }); testWithoutContext( - 'hot reload displays a formatted error message when removing a field from a const class', + 'hot reload displays a formatted error message when removing a field from a const class, and hot restart succeeds', () async { await flutter.run( device: chrome ? GoogleChromeDevice.kChromeDeviceId : FlutterTesterDevices.kTesterDeviceId, additionalCommandArgs: additionalCommandArgs, ); - project.removeFieldFromConstClass(); - expect( + project.removeFieldFromConstClass(); + await expectLater( flutter.hotReload(), throwsA( isA().having( (Exception e) => e.toString(), 'message', - contains(constClassFieldRemovalErrorMessage), + contains('Try performing a hot restart instead.'), ), ), ); + + await expectLater(flutter.hotRestart(), completes); }, ); - - testWithoutContext('hot restart succeeds when removing a field from a const class', () async { - await flutter.run( - device: chrome ? GoogleChromeDevice.kChromeDeviceId : FlutterTesterDevices.kTesterDeviceId, - additionalCommandArgs: additionalCommandArgs, - ); - project.removeFieldFromConstClass(); - await flutter.hotRestart(); - }); }); } diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_test_common.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_test_common.dart index f6cf2435b0ff9..fbf0ac2f9216c 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_test_common.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_test_common.dart @@ -32,21 +32,18 @@ void testAll({bool chrome = false, List additionalCommandArgs = const subscription = flutter.stdout diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart index 95731f80179a7..93c9edc945d70 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart @@ -39,7 +39,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { rootBundle.evict('pubspec.yaml'); rootBundle.load('pubspec.yaml').then((_) { - print('LOADED DATA'); + print('LOADED DATA'); // HOT RELOAD PRINT }, onError: (dynamic error, StackTrace stackTrace) { print('FAILED TO LOAD'); }); @@ -48,8 +48,11 @@ class MyApp extends StatelessWidget { } '''; - void uncommentHotReloadPrint() { - final String newMainContents = main.replaceAll('LOADED DATA', 'SECOND DATA'); + void replaceHotReloadPrint(String newPrint) { + final String newMainContents = main.replaceAll( + RegExp(r"print\('.*'\); // HOT RELOAD PRINT"), + "print('$newPrint'); // HOT RELOAD PRINT", + ); writeFile( fileSystem.path.join(dir.path, 'lib', 'main.dart'), newMainContents, diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset_test_common.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset_test_common.dart index 7525565c3d21b..7f3f5fc28d55a 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset_test_common.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset_test_common.dart @@ -31,9 +31,10 @@ void testAll({bool chrome = false, List additionalCommandArgs = const onFirstLoad = Completer(); final Completer onSecondLoad = Completer(); + final Completer onThirdLoad = Completer(); flutter.stdout.listen((String line) { // If the asset fails to load, this message will be printed instead. @@ -48,6 +49,9 @@ void testAll({bool chrome = false, List additionalCommandArgs = const additionalCommandArgs = const onFirstLoad = Completer(); - final Completer onSecondLoad = Completer(); - - flutter.stdout.listen((String line) { - // If the asset fails to load, this message will be printed instead. - // this indicates that the devFS was not able to locate the asset - // after the hot reload. - if (line.contains('FAILED TO LOAD')) { - fail('Did not load asset: $line'); - } - if (line.contains('LOADED DATA')) { - onFirstLoad.complete(); - } - if (line.contains('SECOND DATA')) { - onSecondLoad.complete(); - } - }); - flutter.stdout.listen(printOnFailure); - await flutter.run( - device: chrome ? GoogleChromeDevice.kChromeDeviceId : FlutterTesterDevices.kTesterDeviceId, - additionalCommandArgs: additionalCommandArgs, - ); - await onFirstLoad.future; - - project.uncommentHotReloadPrint(); + project.replaceHotReloadPrint('THIRD DATA'); await flutter.hotRestart(); - await onSecondLoad.future; + await onThirdLoad.future; }); }); } diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index ee9e9d953d761..5671f31071862 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -140,7 +140,10 @@ abstract final class FlutterTestDriver { _stderr.stream.listen((String message) => _debugPrint(message, topic: '<=stderr=')); } - Future get done async => _process?.exitCode; + /// Completes when process exits with the given exit code. + /// + /// If the process has never been started, complets with `null`. + Future get done async => _process?.exitCode; Future connectToVmService({bool pauseOnExceptions = false}) async { _vmService = await vmServiceConnectUri('$_vmServiceWsUri'); diff --git a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart index f080f6b0514ea..dfe45cbfe9da3 100644 --- a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart +++ b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart @@ -20,21 +20,6 @@ import '../src/context.dart'; import 'test_data/basic_project.dart'; import 'test_utils.dart'; -const List firstLaunchMessages = [ - 'Creating widget preview scaffolding at:', - 'Performing initial build of the Widget Preview Scaffold...', - 'Widget Preview Scaffold initial build complete.', - 'Launching the Widget Preview Scaffold...', - 'Loading previews into the Widget Preview Scaffold...', - 'Done loading previews.', -]; - -const List subsequentLaunchMessages = [ - 'Launching the Widget Preview Scaffold...', - 'Loading previews into the Widget Preview Scaffold...', - 'Done loading previews.', -]; - const List firstLaunchMessagesWeb = [ 'Creating widget preview scaffolding at:', 'Launching the Widget Preview Scaffold...', @@ -68,11 +53,7 @@ void main() { tryToDelete(tempDir); }); - Future runWidgetPreview({ - required List expectedMessages, - bool useWeb = false, - Uri? dtdUri, - }) async { + Future runWidgetPreview({required List expectedMessages, Uri? dtdUri}) async { expect(expectedMessages, isNotEmpty); int i = 0; process = await processManager.start([ @@ -80,10 +61,7 @@ void main() { 'widget-preview', 'start', '--verbose', - if (useWeb) - '--${WidgetPreviewStartCommand.kHeadlessWeb}' - else - '--${WidgetPreviewStartCommand.kUseFlutterDesktop}', + '--${WidgetPreviewStartCommand.kHeadless}', if (dtdUri != null) '--${FlutterGlobalOptions.kDtdUrl}=$dtdUri', ], workingDirectory: tempDir.path); @@ -120,28 +98,15 @@ void main() { group('flutter widget-preview start', () { testWithoutContext('smoke test', () async { - await runWidgetPreview(expectedMessages: firstLaunchMessages); - }); - - testWithoutContext('web smoke test', () async { - await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb, useWeb: true); - }); - - testWithoutContext('does not rebuild project on subsequent runs', () async { - // The first run of 'flutter widget-preview start' should generate a new preview scaffold and - // pre-build the application. - await runWidgetPreview(expectedMessages: firstLaunchMessages); - - // We shouldn't regenerate the scaffold after the initial run. - await runWidgetPreview(expectedMessages: subsequentLaunchMessages); + await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb); }); - testWithoutContext('does not recreate project on subsequent --web runs', () async { - // The first run of 'flutter widget-preview start --web' should generate a new preview scaffold - await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb, useWeb: true); + testWithoutContext('does not recreate project on subsequent runs', () async { + // The first run of 'flutter widget-preview start' should generate a new preview scaffold + await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb); // We shouldn't regenerate the scaffold after the initial run. - await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb, useWeb: true); + await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb); }); testUsingContext('can connect to an existing DTD instance', () async { @@ -169,11 +134,7 @@ void main() { await dtdConnection.streamListen(kWidgetPreviewScaffoldStream); // Start the widget preview and wait for the 'Connected' event. - await runWidgetPreview( - expectedMessages: firstLaunchMessagesWeb, - useWeb: true, - dtdUri: dtdUri, - ); + await runWidgetPreview(expectedMessages: firstLaunchMessagesWeb, dtdUri: dtdUri); await completer.future; }); }); diff --git a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart index fdb0ee508f3ce..d422cecfcfc20 100644 --- a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart @@ -58,7 +58,11 @@ void main() { final ProcessResult result = await Process.run( xcodeBackendPath, ['build'], - environment: {'CONFIGURATION': 'Debug', 'ACTION': 'install'}, + environment: { + 'CONFIGURATION': 'Debug', + 'ACTION': 'install', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, ); expect(result.stderr, contains('warning: Flutter archive not built in Release mode.')); expect(result.exitCode, isNot(0)); diff --git a/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart b/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart deleted file mode 100644 index 95c54871fa4b8..0000000000000 --- a/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file/file.dart'; -import 'package:flutter_tools/src/base/io.dart'; - -import '../src/common.dart'; -import 'test_utils.dart'; - -void main() { - late Directory tempDir; - late Directory projectDir; - - setUpAll(() async { - tempDir = createResolvedTempDirectorySync('xcode_dev_dependencies_test.'); - projectDir = tempDir.childDirectory('project')..createSync(); - final Directory tempPluginADir = tempDir.childDirectory('plugin_a')..createSync(); - - // Create a Flutter project. - await processManager.run([ - flutterBin, - 'create', - projectDir.path, - '--project-name=testapp', - ], workingDirectory: projectDir.path); - - // Create a Flutter plugin to add as a dev dependency to the Flutter project. - await processManager.run([ - flutterBin, - 'create', - tempPluginADir.path, - '--template=plugin', - '--project-name=plugin_a', - '--platforms=ios,macos', - ], workingDirectory: tempPluginADir.path); - - // Add a dev dependency on plugin_a - await processManager.run([ - flutterBin, - 'pub', - 'add', - 'dev:plugin_a', - '--path', - tempPluginADir.path, - ], workingDirectory: projectDir.path); - }); - - tearDownAll(() { - tryToDelete(tempDir); - }); - - group( - 'Xcode build iOS app', - () { - test('succeeds after flutter build ios --config-only', () async { - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('fails in Debug mode if dev dependencies disabled', () async { - // Disable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); - - group( - 'Xcode build iOS module', - () { - test('succeeds after flutter build ios --config-only', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('abc fails in Debug mode if dev dependencies disabled', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - // Disable dev dependencies by generating release configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); - - group( - 'Xcode build macOS app', - () { - test('succeeds after flutter build macos --config-only', () async { - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'error: Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('fails in Debug mode if dev dependencies disabled', () async { - // Disable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'error: Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); -} diff --git a/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart b/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart new file mode 100644 index 0000000000000..02b6b5d5c5df2 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart @@ -0,0 +1,588 @@ +// Copyright 2014 The Flutter Authors. 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/base/file_system.dart'; +import 'package:flutter_tools/src/base/io.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +void main() { + late Directory tempDir; + late Directory projectDir; + + setUpAll(() async { + tempDir = createResolvedTempDirectorySync('xcode_dev_dependencies_test.'); + projectDir = tempDir.childDirectory('project')..createSync(); + final Directory tempPluginADir = tempDir.childDirectory('plugin_a')..createSync(); + + // Create a Flutter project. + await processManager.run([ + flutterBin, + 'create', + projectDir.path, + '--project-name=testapp', + ], workingDirectory: projectDir.path); + + // Create a Flutter plugin to add as a dev dependency to the Flutter project. + await processManager.run([ + flutterBin, + 'create', + tempPluginADir.path, + '--template=plugin', + '--project-name=plugin_a', + '--platforms=ios,macos', + ], workingDirectory: tempPluginADir.path); + + // Add a dev dependency on plugin_a + await processManager.run([ + flutterBin, + 'pub', + 'add', + 'dev:plugin_a', + '--path', + tempPluginADir.path, + ], workingDirectory: projectDir.path); + }); + + tearDownAll(() { + tryToDelete(tempDir); + }); + + group( + 'Xcode build iOS app', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS Simulator', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--release', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); + + group( + 'Xcode build iOS module', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); + + group( + 'Xcode build macOS app', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--release', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); +} diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index fada2a4a5156c..58d694952e8eb 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -493,7 +493,6 @@ class TestFeatureFlags implements FeatureFlags { this.isCliAnimationEnabled = true, this.isNativeAssetsEnabled = false, this.isSwiftPackageManagerEnabled = false, - this.isExplicitPackageDependenciesEnabled = false, }); @override @@ -529,9 +528,6 @@ class TestFeatureFlags implements FeatureFlags { @override final bool isSwiftPackageManagerEnabled; - @override - final bool isExplicitPackageDependenciesEnabled; - @override bool isEnabled(Feature feature) { return switch (feature) { @@ -548,6 +544,21 @@ class TestFeatureFlags implements FeatureFlags { _ => false, }; } + + @override + List get allFeatures => const [ + flutterWebFeature, + flutterLinuxDesktopFeature, + flutterMacOSDesktopFeature, + flutterWindowsDesktopFeature, + flutterAndroidFeature, + flutterIOSFeature, + flutterFuchsiaFeature, + flutterCustomDevicesFeature, + cliAnimation, + nativeAssets, + swiftPackageManager, + ]; } class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { diff --git a/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart b/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart index 0a8db50894b33..6e72fb1da42c2 100644 --- a/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart +++ b/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. @Tags(['flutter-test-driver']) -@Skip('https://github.com/flutter/flutter/issues/169304') library; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart b/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart index 7064367ee05a8..7062b6e447955 100644 --- a/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart +++ b/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. @Tags(['flutter-test-driver']) -@Skip('https://github.com/flutter/flutter/issues/169304') library; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart index 9c35bb76157c8..f71a333cab06e 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_web_errors_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. +@TestOn('linux') // https://github.com/flutter/flutter/issues/170062 @Tags(['flutter-test-driver']) library; @@ -9,11 +10,5 @@ import '../integration.shard/test_data/hot_reload_errors_common.dart'; import '../src/common.dart'; void main() { - testAll( - chrome: true, - additionalCommandArgs: ['--web-experimental-hot-reload'], - // TODO(srujzs): Remove this custom message once we have the delta inspector emitting the same - // string as the VM. - constClassFieldRemovalErrorMessage: 'Const class cannot remove fields', - ); + testAll(chrome: true, additionalCommandArgs: ['--web-experimental-hot-reload']); } 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 a388b3afd242d..5763757c3d34b 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 @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart b/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart index 542e728e3b7e2..ccb808f225a28 100644 --- a/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_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. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart b/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart index 6b0ab1447bb02..4f1440423b130 100644 --- a/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart +++ b/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_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. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/test_data/expression_evaluation_web_common.dart b/packages/flutter_tools/test/web.shard/test_data/expression_evaluation_web_common.dart index c3eb5114c3523..0491f5d831657 100644 --- a/packages/flutter_tools/test/web.shard/test_data/expression_evaluation_web_common.dart +++ b/packages/flutter_tools/test/web.shard/test_data/expression_evaluation_web_common.dart @@ -70,60 +70,19 @@ Future testAll({required bool useDDCLibraryBundleFormat}) async { await failToEvaluateExpression(flutter); }); - testWithoutContext('shows no native javascript objects in static scope', () async { + testWithoutContext('can evaluate expressions in library, top level and build method', () async { await start(expressionEvaluation: true); - await breakInTopLevelFunction(flutter); - await checkStaticScope(flutter); - }); - testWithoutContext('can handle compilation errors', () async { - await start(expressionEvaluation: true); - await breakInTopLevelFunction(flutter); - await evaluateErrorExpressions(flutter); - }); - - testWithoutContext('can evaluate trivial expressions in top level function', () async { - await start(expressionEvaluation: true); - await breakInTopLevelFunction(flutter); - await evaluateTrivialExpressions(flutter); - }); - - testWithoutContext('can evaluate trivial expressions in build method', () async { - await start(expressionEvaluation: true); - await breakInBuildMethod(flutter); - await evaluateTrivialExpressions(flutter); - }); - - testWithoutContext('can evaluate complex expressions in top level function', () async { - await start(expressionEvaluation: true); - await breakInTopLevelFunction(flutter); - await evaluateComplexExpressions(flutter); - }); - - testWithoutContext('can evaluate complex expressions in build method', () async { - await start(expressionEvaluation: true); - await breakInBuildMethod(flutter); - await evaluateComplexExpressions(flutter); - }); - - testWithoutContext('can evaluate trivial expressions in library without pause', () async { - await start(expressionEvaluation: true); await evaluateTrivialExpressionsInLibrary(flutter); - }); - - testWithoutContext('can evaluate complex expressions in library without pause', () async { - await start(expressionEvaluation: true); await evaluateComplexExpressionsInLibrary(flutter); - }); - - testWithoutContext('evaluated expression includes web library environment defines', () async { - await start(expressionEvaluation: true); await evaluateWebLibraryBooleanFromEnvironmentInLibrary(flutter); - }); - testWithoutContext('evaluated expression includes correctly mapped stack trace', () async { - await start(expressionEvaluation: true); await breakInTopLevelFunction(flutter); + await checkStaticScope(flutter); + await evaluateErrorExpressions(flutter); + await evaluateTrivialExpressions(flutter); + await evaluateComplexExpressions(flutter); + // Test that the call comes from some Dart getter called `current` (the // location of which will be compiler-specific) and that the lines and // file name of the current location is correct and reports a Dart path. @@ -140,6 +99,10 @@ Future testAll({required bool useDDCLibraryBundleFormat}) async { end = stackTrace.indexOf('package:test/main.dart 15:7', end); return end != -1; }); + + await breakInBuildMethod(flutter); + await evaluateTrivialExpressions(flutter); + await evaluateComplexExpressions(flutter); }); }); @@ -190,35 +153,17 @@ Future testAll({required bool useDDCLibraryBundleFormat}) async { await failToEvaluateExpression(flutter); }); - testWithoutContext('can evaluate trivial expressions in a test', () async { - await startPaused(expressionEvaluation: true); - await breakInMethod(flutter); - await evaluateTrivialExpressions(flutter); - }); - - testWithoutContext('can evaluate complex expressions in a test', () async { + testWithoutContext('can evaluate expressions in a test', () async { await startPaused(expressionEvaluation: true); - await breakInMethod(flutter); - await evaluateComplexExpressions(flutter); - }); - testWithoutContext('can evaluate trivial expressions in library without pause', () async { - await startPaused(expressionEvaluation: true); await evaluateTrivialExpressionsInLibrary(flutter); - }); - - testWithoutContext('can evaluate complex expressions in library without pause', () async { - await startPaused(expressionEvaluation: true); await evaluateComplexExpressionsInLibrary(flutter); - }); - testWithoutContext('evaluated expression includes web library environment defines', () async { - await startPaused(expressionEvaluation: true); await evaluateWebLibraryBooleanFromEnvironmentInLibrary(flutter); - }); - testWithoutContext('evaluated expression includes correctly mapped stack trace', () async { - await startPaused(expressionEvaluation: true); await breakInMethod(flutter); + await evaluateTrivialExpressions(flutter); + await evaluateComplexExpressions(flutter); + await evaluateStackTraceCurrent(flutter, (String stackTrace) { final Iterable matches = stackTraceCurrentRegexp.allMatches(stackTrace); if (matches.length != 1) { diff --git a/packages/flutter_tools/test/web.shard/test_data/hot_restart_web_test_common.dart b/packages/flutter_tools/test/web.shard/test_data/hot_restart_web_test_common.dart index add4581c3745d..cbcc9c4449d83 100644 --- a/packages/flutter_tools/test/web.shard/test_data/hot_restart_web_test_common.dart +++ b/packages/flutter_tools/test/web.shard/test_data/hot_restart_web_test_common.dart @@ -84,31 +84,9 @@ Future _testProject( tryToDelete(tempDir); }); - testWithoutContext('$testName: hot restart works without error', () async { - flutter.stdout.listen(printOnFailure); - await flutter.run( - device: GoogleChromeDevice.kChromeDeviceId, - additionalCommandArgs: [ - '--verbose', - if (useDDCLibraryBundleFormat) - '--web-experimental-hot-reload' - else - '--no-web-experimental-hot-reload', - ], - ); - await flutter.hotRestart(); - }); - testWithoutContext( - '$testName: newly added code executes during hot restart - canvaskit', + '$testName: hot restart works without error and newly added code executes', () async { - final Completer completer = Completer(); - final StreamSubscription subscription = flutter.stdout.listen((String line) { - printOnFailure(line); - if (line.contains('(((((RELOAD WORKED)))))')) { - completer.complete(); - } - }); await flutter.run( device: GoogleChromeDevice.kChromeDeviceId, additionalCommandArgs: [ @@ -119,6 +97,16 @@ Future _testProject( '--no-web-experimental-hot-reload', ], ); + // hot restart works without error + await flutter.hotRestart(); + + final Completer completer = Completer(); + final StreamSubscription subscription = flutter.stdout.listen((String line) { + printOnFailure(line); + if (line.contains('(((((RELOAD WORKED)))))')) { + completer.complete(); + } + }); project.uncommentHotReloadPrint(); try { await flutter.hotRestart(); @@ -127,7 +115,5 @@ Future _testProject( await subscription.cancel(); } }, - // Skipped for https://github.com/flutter/flutter/issues/110879. - skip: true, ); } diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/.gitignore b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/.gitignore index 79c113f9b5017..c08861603ad68 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/.gitignore +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/.gitignore @@ -27,7 +27,6 @@ migrate_working_dir/ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .pub-cache/ .pub/ diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart index 641c2fbdf9681..00f480eb8cd75 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart @@ -74,13 +74,13 @@ class ZoomControls extends StatelessWidget { void _zoomIn() { _transformationController.value = Matrix4.copy( _transformationController.value, - ).scaled(1.1); + ).scaledByDouble(1.1, 1.1, 1.1, 1); } void _zoomOut() { final Matrix4 updated = Matrix4.copy( _transformationController.value, - ).scaled(0.9); + ).scaledByDouble(0.9, 0.9, 0.9, 1); // Don't allow for zooming out past the original size of the widget. // Assumes scaling is evenly applied to the entire matrix. diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview.dart index 12c4975356171..8e4494a6c5f27 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview.dart @@ -28,6 +28,7 @@ class WidgetPreview { this.textScaleFactor, this.brightness, this.theme, + this.localizations, }); /// A description to be displayed alongside the preview. @@ -63,12 +64,25 @@ class WidgetPreview { /// If not provided, the current system default brightness will be used. final Brightness? brightness; + /// A callback to return a localization configuration to be applied to the + /// previewed [Widget]. + /// + /// Note: this must be a reference to a static, public function defined as + /// either a top-level function or static member in a class. + final PreviewLocalizationsData? localizations; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { properties ..add(DiagnosticsProperty('name', name, ifNull: 'not set')) ..add(DiagnosticsProperty('size', size)) ..add(DiagnosticsProperty('textScaleFactor', textScaleFactor)) ..add(DiagnosticsProperty('theme', theme)) - ..add(DiagnosticsProperty('brightness', brightness)); + ..add(DiagnosticsProperty('brightness', brightness)) + ..add( + DiagnosticsProperty( + 'localizations', + localizations, + ), + ); } } diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart index 347c24915d0c3..ee1cdbd1b5583 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart @@ -322,6 +322,11 @@ class WidgetPreviewWidgetState extends State { child: preview, ); + preview = WidgetPreviewLocalizations( + localizationsData: widget.preview.localizations, + child: preview, + ); + preview = Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -472,6 +477,72 @@ class WidgetPreviewMediaQueryOverride extends StatelessWidget { } } +/// Wraps [child] with a [Localizations] with localization data from +/// [localizationsData]. +class WidgetPreviewLocalizations extends StatefulWidget { + const WidgetPreviewLocalizations({ + super.key, + required this.localizationsData, + required this.child, + }); + + final PreviewLocalizationsData? localizationsData; + final Widget child; + + @override + State createState() => + _WidgetPreviewLocalizationsState(); +} + +class _WidgetPreviewLocalizationsState + extends State { + PreviewLocalizationsData get _localizationsData => widget.localizationsData!; + late final LocalizationsResolver _localizationsResolver = + LocalizationsResolver( + supportedLocales: _localizationsData.supportedLocales, + locale: _localizationsData.locale, + localeListResolutionCallback: + _localizationsData.localeListResolutionCallback, + localeResolutionCallback: _localizationsData.localeResolutionCallback, + localizationsDelegates: _localizationsData.localizationsDelegates, + ); + + @override + void didUpdateWidget(WidgetPreviewLocalizations oldWidget) { + super.didUpdateWidget(oldWidget); + final PreviewLocalizationsData? localizationsData = + widget.localizationsData; + if (localizationsData == null) { + return; + } + _localizationsResolver.update( + supportedLocales: localizationsData.supportedLocales, + locale: localizationsData.locale, + localeListResolutionCallback: + localizationsData.localeListResolutionCallback, + localeResolutionCallback: localizationsData.localeResolutionCallback, + localizationsDelegates: localizationsData.localizationsDelegates, + ); + } + + @override + Widget build(BuildContext context) { + if (widget.localizationsData == null) { + return widget.child; + } + return ListenableBuilder( + listenable: _localizationsResolver, + builder: (context, _) { + return Localizations( + locale: _localizationsResolver.locale, + delegates: _localizationsResolver.localizationsDelegates.toList(), + child: widget.child, + ); + }, + ); + } +} + /// An [InheritedWidget] that propagates the current size of the /// WidgetPreviewScaffold. /// diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.lock b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.lock new file mode 100644 index 0000000000000..3a0dcd9af54ca --- /dev/null +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.lock @@ -0,0 +1,378 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: "direct main" + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: "direct main" + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: "direct main" + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: "direct main" + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: "direct main" + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + dtd: + dependency: "direct main" + description: + name: dtd + sha256: "14a0360d898ded87c3d99591fc386b8a6ea5d432927bee709b22130cd25b993a" + url: "https://pub.dev" + source: hosted + version: "2.5.1" + fake_async: + dependency: "direct main" + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + file: + dependency: "direct main" + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct main" + description: + name: flutter_lints + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_test: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + http_parser: + dependency: "direct main" + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + json_rpc_2: + dependency: "direct main" + description: + name: json_rpc_2 + sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker: + dependency: "direct main" + description: + name: leak_tracker + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" + url: "https://pub.dev" + source: hosted + version: "11.0.1" + leak_tracker_flutter_testing: + dependency: "direct main" + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: "direct main" + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: "direct main" + description: + name: lints + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 + url: "https://pub.dev" + source: hosted + version: "6.0.0" + matcher: + dependency: "direct main" + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: "direct main" + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: "direct main" + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + plugin_platform_interface: + dependency: "direct main" + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: "direct main" + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: "direct main" + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: "direct main" + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: "direct main" + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: "direct main" + description: + name: test_api + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + typed_data: + dependency: "direct main" + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + unified_analytics: + dependency: "direct main" + description: + name: unified_analytics + sha256: c8abdcad84b55b78f860358aae90077b8f54f98169a75e16d97796a1b3c95590 + url: "https://pub.dev" + source: hosted + version: "8.0.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: "direct main" + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: "direct main" + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: "direct main" + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: "direct main" + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: "direct main" + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: "direct main" + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: "direct main" + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + vector_math: + dependency: "direct main" + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: "direct main" + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + web: + dependency: "direct main" + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: "direct main" + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" +sdks: + dart: ">=3.8.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml index 3109d41c2374d..b4c8433801137 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml @@ -13,52 +13,52 @@ dependencies: sdk: flutter # These will be replaced with proper constraints after the template is hydrated. dtd: 2.5.1 - flutter_lints: 5.0.0 + flutter_lints: 6.0.0 stack_trace: 1.12.1 url_launcher: 6.3.1 - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - json_rpc_2: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - lints: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - unified_analytics: 8.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_android: 6.3.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_ios: 6.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_linux: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_macos: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_windows: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + async: 2.13.0 + boolean_selector: 2.1.2 + characters: 1.4.0 + clock: 1.1.2 + collection: 1.19.1 + convert: 3.1.2 + crypto: 3.0.6 + fake_async: 1.3.3 + file: 7.0.1 + http: 1.4.0 + http_parser: 4.1.2 + json_rpc_2: 3.0.3 + leak_tracker: 11.0.1 + leak_tracker_flutter_testing: 3.0.10 + leak_tracker_testing: 3.0.2 + lints: 6.0.0 + matcher: 0.12.17 + material_color_utilities: 0.11.1 + meta: 1.16.0 + path: 1.9.1 + plugin_platform_interface: 2.1.8 + source_span: 1.10.1 + stream_channel: 2.1.4 + string_scanner: 1.4.1 + term_glyph: 1.2.2 + test_api: 0.7.6 + typed_data: 1.4.0 + unified_analytics: 8.0.1 + url_launcher_android: 6.3.16 + url_launcher_ios: 6.3.3 + url_launcher_linux: 3.2.1 + url_launcher_macos: 3.2.2 + url_launcher_platform_interface: 2.3.2 + url_launcher_web: 2.4.1 + url_launcher_windows: 3.1.4 + vector_math: 2.2.0 + vm_service: 15.0.2 + web: 1.1.1 + web_socket: 1.0.1 + web_socket_channel: 3.0.3 flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 10cc +# PUBSPEC CHECKSUM: qqjk1 diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/localizations_test.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/localizations_test.dart new file mode 100644 index 0000000000000..5310a4cdf6860 --- /dev/null +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/localizations_test.dart @@ -0,0 +1,77 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widget_previews.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:widget_preview_scaffold/src/widget_preview.dart'; +import 'package:widget_preview_scaffold/src/widget_preview_rendering.dart'; + +import 'utils/localizations_utils.dart'; +import 'utils/widget_preview_scaffold_test_utils.dart'; + +void expectLocalization({ + required BuildContext context, + required PreviewLocalizationsData? expected, +}) { + final AppLocalizations? actual = AppLocalizations.of(context); + expect(actual, isA()); + if (expected == null) { + expect(actual, isNull); + } + expect(actual!.localeName, expected!.locale?.languageCode); + expect( + AppLocalizations.localizationsDelegates, + expected.localizationsDelegates, + ); +} + +WidgetPreviewerWidgetScaffolding previewForLocalizations({ + required Key key, + PreviewLocalizationsData? previewLocalizationsData, +}) { + return WidgetPreviewerWidgetScaffolding( + child: WidgetPreviewWidget( + preview: WidgetPreview( + builder: () => Text('Foo', key: key), + localizations: previewLocalizationsData, + ), + ), + ); +} + +void main() { + testWidgets( + 'Localization data is correctly propagated down to the previewed widget', + (tester) async { + final key = GlobalKey(); + PreviewLocalizationsData previewLocalizationsData = forLocale('en'); + + // Check that both en and es localizations are available to the previewed widget. + WidgetPreviewerWidgetScaffolding widgetPreview = previewForLocalizations( + key: key, + previewLocalizationsData: previewLocalizationsData, + ); + await tester.pumpWidget(widgetPreview); + + expectLocalization( + context: key.currentContext!, + expected: previewLocalizationsData, + ); + + previewLocalizationsData = forLocale('es'); + widgetPreview = previewForLocalizations( + key: key, + previewLocalizationsData: previewLocalizationsData, + ); + await tester.pumpWidget(widgetPreview); + + expectLocalization( + context: key.currentContext!, + expected: previewLocalizationsData, + ); + }, + ); +} diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/soft_restart_test.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/soft_restart_test.dart index 6d7122e9c3e7d..db2c5f667627a 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/soft_restart_test.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/soft_restart_test.dart @@ -10,7 +10,7 @@ import 'package:widget_preview_scaffold/src/controls.dart'; import 'package:widget_preview_scaffold/src/widget_preview.dart'; import 'package:widget_preview_scaffold/src/widget_preview_rendering.dart'; -import 'widget_preview_scaffold_test_utils.dart'; +import 'utils/widget_preview_scaffold_test_utils.dart'; void main() { testWidgets( diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/theming_test.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/theming_test.dart index 71b180bd13960..0987484eea26e 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/theming_test.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/theming_test.dart @@ -10,7 +10,7 @@ import 'package:widget_preview_scaffold/src/controls.dart'; import 'package:widget_preview_scaffold/src/widget_preview.dart'; import 'package:widget_preview_scaffold/src/widget_preview_rendering.dart'; -import 'widget_preview_scaffold_test_utils.dart'; +import 'utils/widget_preview_scaffold_test_utils.dart'; // Applies localization theming allowing for direct comparison of `themeData` against the theme // data retreived from the tree. diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/utils/localizations_utils.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/utils/localizations_utils.dart new file mode 100644 index 0000000000000..b3edb2d7a7908 --- /dev/null +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/utils/localizations_utils.dart @@ -0,0 +1,104 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widget_previews.dart'; +import 'package:flutter/widgets.dart'; + +PreviewLocalizationsData forLocale(String locale) { + return PreviewLocalizationsData( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + ); +} + +// These classes were originally generated by flutter gen-l10n for the +// gen_l10n_example application. +abstract class AppLocalizations { + AppLocalizations(String locale) + : // This isn't canonicalized, otherwise we'd need to depend on package:intl + // just for testing and we don't particularly care about this value. + localeName = locale; + + final String localeName; + + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + static const LocalizationsDelegate delegate = + _AppLocalizationsDelegate(); + + static const List> localizationsDelegates = + >[ + delegate, + // The following delegates should also technically be included, but we + // omit them to avoid the dependency on package:flutter_localizations + // just for testing. + // + // GlobalMaterialLocalizations.delegate, + // GlobalCupertinoLocalizations.delegate, + // GlobalWidgetsLocalizations.delegate, + ]; + + static const List supportedLocales = [ + Locale('en'), + Locale('es'), + ]; + + String get helloWorld; +} + +class _AppLocalizationsDelegate + extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => + ['en', 'es'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': + return AppLocalizationsEn(); + case 'es': + return AppLocalizationsEs(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); +} + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([super.locale = 'en']); + + @override + String get helloWorld => 'Hello World!'; +} + +/// The translations for Spanish Castilian (`es`). +class AppLocalizationsEs extends AppLocalizations { + AppLocalizationsEs([super.locale = 'es']); + + @override + String get helloWorld => '¡Hola Mundo!'; +} diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_preview_scaffold_test_utils.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/utils/widget_preview_scaffold_test_utils.dart similarity index 100% rename from packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_preview_scaffold_test_utils.dart rename to packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/utils/widget_preview_scaffold_test_utils.dart diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_inspector_test.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_inspector_test.dart index 4ff4ef357b92c..396d267cca359 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_inspector_test.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/test/widget_inspector_test.dart @@ -7,7 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:widget_preview_scaffold/src/widget_preview.dart'; import 'package:widget_preview_scaffold/src/widget_preview_rendering.dart'; -import 'widget_preview_scaffold_test_utils.dart'; +import 'utils/widget_preview_scaffold_test_utils.dart'; void main() { testWidgets( diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index cd36fd6e50035..0a0b22a65fbc6 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -5,35 +5,16 @@ homepage: https://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: 60tfp7 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index e84c4060292da..b6efbcca996f7 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -6,64 +6,20 @@ homepage: https://flutter.dev environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: - process: 5.0.3 - vm_service: 15.0.0 + process: any + vm_service: any - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: any dev_dependencies: - test: 1.26.1 + test: any - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.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.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # 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: e050 +# PUBSPEC CHECKSUM: 67t3ss diff --git a/packages/integration_test/example/.gitignore b/packages/integration_test/example/.gitignore index 47d2423d086cb..72a72ec39b8a9 100644 --- a/packages/integration_test/example/.gitignore +++ b/packages/integration_test/example/.gitignore @@ -24,7 +24,6 @@ **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 124a931ff9469..4413a9f8b3031 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -5,19 +5,15 @@ publish_to: 'none' environment: sdk: ^3.7.0-0 flutter: ">=1.6.7" +resolution: workspace + dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.8 - web: 1.1.1 + web: any - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -28,65 +24,13 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.26.1 - pedantic: 1.11.1 + test: any # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 82.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 7.4.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - args: 2.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cli_config: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - coverage: 1.13.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - frontend_server_client: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - glob: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_multi_server: 3.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - io: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - js: 0.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - logging: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - mime: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - package_config: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_static: 1.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - shelf_web_socket: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_map_stack_trace: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_maps: 0.10.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web_socket_channel: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2fd8 +# PUBSPEC CHECKSUM: rhtu4l diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 7e932ea46b428..3b1f88ce3c620 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -12,17 +12,12 @@ flutter: environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -dev_dependencies: - pedantic: 1.11.1 -# PUBSPEC CHECKSUM: de8e +# PUBSPEC CHECKSUM: h86dcv diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index bc6c6f4531251..018f27cafd59d 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -5,6 +5,8 @@ publish_to: none environment: sdk: ^3.7.0-0 +resolution: workspace + dependencies: flutter: sdk: flutter @@ -12,40 +14,14 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - path: 1.9.1 - vm_service: 15.0.0 - - async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker: 11.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_flutter_testing: 3.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - matcher: 0.12.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - source_span: 1.10.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.12.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - string_scanner: 1.4.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.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: any + vm_service: any + dev_dependencies: flutter_goldens: sdk: flutter - crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: plugin: @@ -56,4 +32,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 26ea +# PUBSPEC CHECKSUM: 768bse diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000000000..5a54f48124334 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1108 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _discoveryapis_commons: + dependency: "direct main" + description: + name: _discoveryapis_commons + sha256: "113c4100b90a5b70a983541782431b82168b3cae166ab130649c36eb3559d498" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + _fe_analyzer_shared: + dependency: "direct main" + description: + name: _fe_analyzer_shared + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f + url: "https://pub.dev" + source: hosted + version: "82.0.0" + adaptive_breakpoints: + dependency: "direct main" + description: + name: adaptive_breakpoints + sha256: "56dd5f1016f4d5732b80628d1b63a29d8c9cabe4d66a8a5fe63fdbec7b3af5cd" + url: "https://pub.dev" + source: hosted + version: "0.1.7" + analyzer: + dependency: "direct main" + description: + name: analyzer + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" + url: "https://pub.dev" + source: hosted + version: "7.4.5" + animations: + dependency: "direct main" + description: + name: animations + sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb + url: "https://pub.dev" + source: hosted + version: "2.0.11" + archive: + dependency: "direct main" + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: "direct main" + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + assets_for_android_views: + dependency: transitive + description: + path: "dev/integration_tests/assets_for_android_views" + ref: "64d0f6051b9b7b9933d3d16194170a38f544634a" + resolved-ref: "64d0f6051b9b7b9933d3d16194170a38f544634a" + url: "https://github.com/flutter/goldens.git" + source: git + version: "0.2.0" + async: + dependency: "direct main" + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: "direct main" + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: "direct main" + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: "direct main" + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_config: + dependency: "direct main" + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + cli_util: + dependency: "direct main" + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + clock: + dependency: "direct main" + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: "direct main" + description: + name: code_assets + sha256: "2d1f99d221a174275a7992152039264dcb69521bb61fb541544187b0eeeda018" + url: "https://pub.dev" + source: hosted + version: "0.19.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: "direct main" + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: "direct main" + description: + name: coverage + sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 + url: "https://pub.dev" + source: hosted + version: "1.14.1" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + csslib: + dependency: "direct main" + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_style: + dependency: "direct main" + description: + name: dart_style + sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + device_info: + dependency: "direct main" + description: + name: device_info + sha256: f4a8156cb7b7480d969cb734907d18b333c8f0bc0b1ad0b342cdcecf30d62c48 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + device_info_platform_interface: + dependency: "direct main" + description: + name: device_info_platform_interface + sha256: b148e0bf9640145d09a4f8dea96614076f889e7f7f8b5ecab1c7e5c2dbc73c1b + url: "https://pub.dev" + source: hosted + version: "2.0.1" + fake_async: + dependency: "direct main" + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: "direct main" + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + ffigen: + dependency: "direct main" + description: + name: ffigen + sha256: "72d732c33557fc0ca9b46379d3deff2dadbdc539696dc0b270189e2989be20ef" + url: "https://pub.dev" + source: hosted + version: "18.1.0" + file: + dependency: "direct main" + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_testing: + dependency: "direct main" + description: + name: file_testing + sha256: eb0c85fd118ddc0d41c295c09f64e0924c256b071087cdc9828d5372c80d554d + url: "https://pub.dev" + source: hosted + version: "3.0.2" + fixnum: + dependency: "direct main" + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_gallery_assets: + dependency: "direct main" + description: + name: flutter_gallery_assets + sha256: f8fecfeebcfbe80a2fabc00c0834046890abe681f59d3e2c5b1028faf887d94b + url: "https://pub.dev" + source: hosted + version: "1.0.2" + flutter_lints: + dependency: "direct main" + description: + name: flutter_lints + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_localized_locales: + dependency: "direct main" + description: + name: flutter_localized_locales + sha256: "478d10535edf07292e34cb4c757882edeeaf96d5e3dbb04b42733038bd41dd3f" + url: "https://pub.dev" + source: hosted + version: "2.0.5" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + frontend_server_client: + dependency: "direct main" + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + gcloud: + dependency: "direct main" + description: + name: gcloud + sha256: caa415a0145ec8afac457322872c3e8b38379a88800d2944c53798ea8fbce386 + url: "https://pub.dev" + source: hosted + version: "0.8.19" + glob: + dependency: "direct main" + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + google_identity_services_web: + dependency: "direct main" + description: + name: google_identity_services_web + sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" + url: "https://pub.dev" + source: hosted + version: "0.3.3+1" + google_mobile_ads: + dependency: "direct main" + description: + name: google_mobile_ads + sha256: e2d18992d30b2be77cb6976b931112fc3c4612feffb5eb7a8b036bd7a64934da + url: "https://pub.dev" + source: hosted + version: "5.1.0" + googleapis: + dependency: "direct main" + description: + name: googleapis + sha256: "8a8c311723162af077ca73f94b823b97ff68770d966e29614d20baca9fdb490a" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + googleapis_auth: + dependency: "direct main" + description: + name: googleapis_auth + sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938 + url: "https://pub.dev" + source: hosted + version: "1.6.0" + hooks: + dependency: "direct main" + description: + name: hooks + sha256: c29b5d113b093995426c9d2d4ce157902f04d426d9fb44206f88d2da7ae3e0f2 + url: "https://pub.dev" + source: hosted + version: "0.19.1" + html: + dependency: "direct main" + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" + http: + dependency: "direct main" + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + http_multi_server: + dependency: "direct main" + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: "direct main" + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + io: + dependency: "direct main" + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + isolate: + dependency: "direct main" + description: + name: isolate + sha256: "3554ab10fdeec965d27e0074c913ccb2229887633da080d2b35a6322da14938b" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + js: + dependency: "direct main" + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: "direct main" + description: + name: leak_tracker + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" + url: "https://pub.dev" + source: hosted + version: "11.0.1" + leak_tracker_flutter_testing: + dependency: "direct main" + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: "direct main" + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: "direct main" + description: + name: lints + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 + url: "https://pub.dev" + source: hosted + version: "6.0.0" + logging: + dependency: "direct main" + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: "direct main" + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: "direct main" + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: "direct main" + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + metrics_center: + dependency: "direct main" + description: + name: metrics_center + sha256: "0379309f4b36ea6b2af042fb8cfd045e611a929758b18b7382a066d65d1e6bbb" + url: "https://pub.dev" + source: hosted + version: "1.0.13" + mime: + dependency: "direct main" + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + native_toolchain_c: + dependency: "direct main" + description: + name: native_toolchain_c + sha256: "17cd04ceb82cb889250475a32bdeabdb997ad67bc99cc630329d79117486733b" + url: "https://pub.dev" + source: hosted + version: "0.16.1" + nested: + dependency: "direct main" + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + node_preamble: + dependency: "direct main" + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: "direct main" + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: "direct main" + description: + name: path_provider_android + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + url: "https://pub.dev" + source: hosted + version: "2.2.17" + path_provider_foundation: + dependency: "direct main" + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + path_provider_linux: + dependency: "direct main" + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: "direct main" + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: "direct main" + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + pedantic: + dependency: "direct main" + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + petitparser: + dependency: "direct main" + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + platform: + dependency: "direct main" + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: "direct main" + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pool: + dependency: "direct main" + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process: + dependency: "direct main" + description: + name: process + sha256: "44b4226c0afd4bc3b7c7e67d44c4801abd97103cf0c84609e2654b664ca2798c" + url: "https://pub.dev" + source: hosted + version: "5.0.4" + process_runner: + dependency: "direct main" + description: + name: process_runner + sha256: "4763f660895a1aea3c097bba3204794094b828cb9a279a65a2506a9b93d47d12" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + protobuf: + dependency: "direct main" + description: + name: protobuf + sha256: "579fe5557eae58e3adca2e999e38f02441d8aa908703854a9e0a0f47fa857731" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + pub_semver: + dependency: "direct main" + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: "direct main" + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + quiver: + dependency: "direct main" + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + rally_assets: + dependency: "direct main" + description: + name: rally_assets + sha256: cdd331819d51e58f9d8766c98af99bc0955d1c4b6b306eee4d332d30e9deaa81 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + retry: + dependency: "direct main" + description: + name: retry + sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + scoped_model: + dependency: "direct main" + description: + name: scoped_model + sha256: "8dacc77cb5de78d5e159d54cab883847491a73dfaa3d28c52f4ec8b0be32645b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + shelf: + dependency: "direct main" + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: "direct main" + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: "direct main" + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: "direct main" + description: + name: shelf_web_socket + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + shrine_images: + dependency: "direct main" + description: + name: shrine_images + sha256: "7417da1e83c22f483e222a9d947ffea04b66078c70090072eb0821b89872c26a" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_map_stack_trace: + dependency: "direct main" + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: "direct main" + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: "direct main" + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: "direct main" + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + standard_message_codec: + dependency: "direct main" + description: + name: standard_message_codec + sha256: fc7dd712d191b7e33196a0ecf354c4573492bb95995e7166cb6f73b047f9cae0 + url: "https://pub.dev" + source: hosted + version: "0.0.1+4" + stream_channel: + dependency: "direct main" + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: "direct main" + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + sync_http: + dependency: "direct main" + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: "direct main" + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct main" + description: + name: test + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" + url: "https://pub.dev" + source: hosted + version: "1.26.2" + test_api: + dependency: "direct main" + description: + name: test_api + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + test_core: + dependency: "direct main" + description: + name: test_core + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" + url: "https://pub.dev" + source: hosted + version: "0.6.11" + typed_data: + dependency: "direct main" + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: "direct main" + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: "direct main" + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: "direct main" + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: "direct main" + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: "direct main" + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: "direct main" + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: "direct main" + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + vector_math: + dependency: "direct main" + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a" + url: "https://pub.dev" + source: hosted + version: "2.10.0" + video_player_android: + dependency: "direct main" + description: + name: video_player_android + sha256: "4a5135754a62dbc827a64a42ef1f8ed72c962e191c97e2d48744225c2b9ebb73" + url: "https://pub.dev" + source: hosted + version: "2.8.7" + video_player_avfoundation: + dependency: "direct main" + description: + name: video_player_avfoundation + sha256: "9ee764e5cd2fc1e10911ae8ad588e1a19db3b6aa9a6eb53c127c42d3a3c3f22f" + url: "https://pub.dev" + source: hosted + version: "2.7.1" + video_player_platform_interface: + dependency: "direct main" + description: + name: video_player_platform_interface + sha256: df534476c341ab2c6a835078066fc681b8265048addd853a1e3c78740316a844 + url: "https://pub.dev" + source: hosted + version: "6.3.0" + video_player_web: + dependency: "direct main" + description: + name: video_player_web + sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba + url: "https://pub.dev" + source: hosted + version: "2.3.5" + vm_service: + dependency: "direct main" + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + vm_snapshot_analysis: + dependency: "direct main" + description: + name: vm_snapshot_analysis + sha256: "5a79b9fbb6be2555090f55b03b23907e75d44c3fd7bdd88da09848aa5a1914c8" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + watcher: + dependency: "direct main" + description: + name: watcher + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web: + dependency: "direct main" + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: "direct main" + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: "direct main" + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webdriver: + dependency: "direct main" + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + webkit_inspection_protocol: + dependency: "direct main" + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: ec81f57aa1611f8ebecf1d2259da4ef052281cb5ad624131c93546c79ccc7736 + url: "https://pub.dev" + source: hosted + version: "4.9.0" + webview_flutter_android: + dependency: "direct main" + description: + name: webview_flutter_android + sha256: "47a8da40d02befda5b151a26dba71f47df471cddd91dfdb7802d0a87c5442558" + url: "https://pub.dev" + source: hosted + version: "3.16.9" + webview_flutter_platform_interface: + dependency: "direct main" + description: + name: webview_flutter_platform_interface + sha256: "7cb32b21825bd65569665c32bb00a34ded5779786d6201f5350979d2d529940d" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + webview_flutter_wkwebview: + dependency: "direct main" + description: + name: webview_flutter_wkwebview + sha256: a3d461fe3467014e05f3ac4962e5fdde2a4bf44c561cb53e9ae5c586600fdbc3 + url: "https://pub.dev" + source: hosted + version: "3.22.0" + xdg_directories: + dependency: "direct main" + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: "direct main" + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" + yaml_edit: + dependency: "direct main" + description: + name: yaml_edit + sha256: fb38626579fb345ad00e674e2af3a5c9b0cc4b9bfb8fd7f7ff322c7c9e62aef5 + url: "https://pub.dev" + source: hosted + version: "2.2.2" +sdks: + dart: ">=3.9.0-21.0.dev <4.0.0" + flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000000000..ec86223fb04ee --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,217 @@ +name: _flutter_packages + +environment: + sdk: ^3.7.0-0 + +workspace: + - packages/flutter + - packages/flutter/test_private/test + - packages/flutter/test_private + - packages/flutter_driver + - packages/flutter_localizations + - packages/flutter_test + - packages/integration_test + - packages/integration_test/example + - packages/integration_test/integration_test_macos + - packages/fuchsia_remote_debug_protocol + - packages/flutter_web_plugins + - packages/flutter_goldens + - dev/devicelab + - dev/manual_tests + - dev/tracing_tests + - dev/customer_testing + - dev/integration_tests/link_hook + - dev/integration_tests/hook_user_defines + - dev/integration_tests/flavors + - dev/integration_tests/spell_check + - dev/integration_tests/wide_gamut_test + - dev/integration_tests/release_smoke_test + - dev/integration_tests/deferred_components_test + - dev/integration_tests/new_gallery + - dev/integration_tests/web + - dev/integration_tests/ios_add2app_life_cycle/flutterapp + - dev/integration_tests/platform_interaction + - dev/integration_tests/external_textures + - dev/integration_tests/channels + - dev/integration_tests/android_semantics_testing + - dev/integration_tests/ui + - dev/integration_tests/android_views + - dev/integration_tests/ios_platform_view_tests + - dev/integration_tests/flutter_gallery + - dev/integration_tests/android_engine_test + - dev/integration_tests/display_cutout_rotation + - dev/integration_tests/web_e2e_tests + - dev/integration_tests/keyboard_hot_restart + - dev/integration_tests/web_compile_tests + - dev/integration_tests/ios_app_with_extensions + - dev/integration_tests/windows_startup_test + - dev/bots + - dev/forbidden_from_release_tests + - dev/automated_tests + - dev/snippets + - dev/tools + - dev/tools/android_driver_extensions + - dev/tools/gen_keycodes + - dev/tools/gen_defaults + - dev/tools/vitool + - dev/conductor/core + - dev/benchmarks/microbenchmarks + - dev/benchmarks/multiple_flutters/module + - dev/benchmarks/platform_channels_benchmarks + - dev/benchmarks/platform_views_layout + - dev/benchmarks/platform_views_layout_hybrid_composition + - dev/benchmarks/macrobenchmarks + - dev/benchmarks/complex_layout + - dev/benchmarks/imitation_game_flutter + - dev/benchmarks/test_apps/stocks + - dev/a11y_assessments + - examples/image_list + - examples/platform_channel + - examples/layers + - examples/hello_world + - examples/platform_view + - examples/platform_channel_swift + - examples/flutter_view + - examples/texture + - examples/api + - examples/splash + +dependencies: + _discoveryapis_commons: 1.0.7 + _fe_analyzer_shared: 82.0.0 + adaptive_breakpoints: 0.1.7 + analyzer: 7.4.5 + animations: 2.0.11 + archive: 3.6.1 + args: 2.7.0 + async: 2.13.0 + boolean_selector: 2.1.2 + characters: 1.4.0 + checked_yaml: 2.0.4 + cli_config: 0.2.0 + clock: 1.1.2 + code_assets: 0.19.0 + collection: 1.19.1 + convert: 3.1.2 + coverage: 1.14.1 + crypto: 3.0.6 + csslib: 1.0.2 + cupertino_icons: 1.0.8 + device_info: 2.0.3 + device_info_platform_interface: 2.0.1 + fake_async: 1.3.3 + ffi: 2.1.4 + file: 7.0.1 + fixnum: 1.1.1 + flutter_gallery_assets: 1.0.2 + flutter_localized_locales: 2.0.5 + flutter_staggered_grid_view: 0.7.0 + frontend_server_client: 4.0.0 + gcloud: 0.8.19 + glob: 2.1.3 + google_fonts: 6.2.1 + google_identity_services_web: 0.3.3+1 + google_mobile_ads: 5.1.0 + googleapis: 12.0.0 + googleapis_auth: 1.6.0 + hooks: 0.19.1 + html: 0.15.6 + http: 1.4.0 + http_multi_server: 3.2.2 + http_parser: 4.1.2 + intl: 0.20.2 + io: 1.0.5 + isolate: 2.1.1 + js: 0.7.2 + json_annotation: 4.9.0 + leak_tracker: 11.0.1 + leak_tracker_flutter_testing: 3.0.10 + leak_tracker_testing: 3.0.2 + logging: 1.3.0 + matcher: 0.12.17 + material_color_utilities: 0.11.1 + meta: 1.16.0 + metrics_center: 1.0.13 + mime: 2.0.0 + native_toolchain_c: 0.16.1 + nested: 1.0.0 + node_preamble: 2.0.2 + package_config: 2.2.0 + path: 1.9.1 + path_provider: 2.1.5 + path_provider_android: 2.2.17 + path_provider_foundation: 2.4.1 + path_provider_linux: 2.2.1 + path_provider_platform_interface: 2.1.2 + path_provider_windows: 2.3.0 + petitparser: 6.1.0 + platform: 3.1.6 + plugin_platform_interface: 2.1.8 + pool: 1.5.1 + process: 5.0.4 + process_runner: 4.2.0 + protobuf: 4.1.0 + provider: 6.1.5 + pub_semver: 2.2.0 + pubspec_parse: 1.5.0 + rally_assets: 3.0.1 + retry: 3.1.2 + scoped_model: 2.0.0 + shelf: 1.4.2 + shelf_packages_handler: 3.0.2 + shelf_static: 1.1.3 + shelf_web_socket: 2.0.1 + shrine_images: 2.0.2 + source_map_stack_trace: 2.1.2 + source_maps: 0.10.13 + source_span: 1.10.1 + stack_trace: 1.12.1 + standard_message_codec: 0.0.1+4 + stream_channel: 2.1.4 + string_scanner: 1.4.1 + sync_http: 0.3.1 + term_glyph: 1.2.2 + test: 1.26.2 + test_api: 0.7.6 + test_core: 0.6.11 + typed_data: 1.4.0 + url_launcher: 6.3.1 + url_launcher_android: 6.3.16 + url_launcher_ios: 6.3.3 + url_launcher_linux: 3.2.1 + url_launcher_macos: 3.2.2 + url_launcher_platform_interface: 2.3.2 + url_launcher_web: 2.4.1 + url_launcher_windows: 3.1.4 + vector_math: 2.2.0 + video_player: 2.10.0 + video_player_android: 2.8.7 + video_player_avfoundation: 2.7.1 + video_player_platform_interface: 6.3.0 + video_player_web: 2.3.5 + vm_service: 15.0.2 + vm_snapshot_analysis: 0.7.6 + watcher: 1.1.1 + web: 1.1.1 + web_socket: 1.0.1 + web_socket_channel: 3.0.3 + webdriver: 3.1.0 + webkit_inspection_protocol: 1.2.1 + webview_flutter: 4.9.0 + webview_flutter_android: 3.16.9 + webview_flutter_platform_interface: 2.13.0 + webview_flutter_wkwebview: 3.22.0 + xdg_directories: 1.1.0 + xml: 6.5.0 + yaml: 3.1.3 + cli_util: 0.4.2 + dart_style: 3.1.0 + ffigen: 18.1.0 + file_testing: 3.0.2 + flutter_lints: 6.0.0 + lints: 6.0.0 + pedantic: 1.11.1 + quiver: 3.2.2 + yaml_edit: 2.2.2 + +# PUBSPEC CHECKSUM: 51a6er