diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index b7983d7d8244..17a30297da50 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -41581c9a1b909e481c13a2cee7a6e133f7e2ab1e +39585e66c11f0dccbf27089155f2bdc4b28f82d2 diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 6f3299ad195d..a9d110555e65 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -49,6 +49,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v1.0.26 + uses: github/codeql-action/upload-sarif@e2e140ad1441662206e8f97754b166877dfa1c73 # v1.0.26 with: sarif_file: results.sarif diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 1db3ab335b91..836b73586df7 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,6 +1,8 @@ -## NEXT +## 2.7.4 * Updates minimum supported SDK version to Flutter 3.13/Dart 3.1. +* Documents `getExposureOffsetStepSize` to return -1 if the device does not support + exposure compensation. ## 2.7.3 diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 6707962cbc1f..c791d030ca2c 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -221,7 +221,8 @@ abstract class CameraPlatform extends PlatformInterface { /// Gets the supported step size for exposure offset for the selected camera in EV units. /// - /// Returns 0 when the camera supports using a free value without stepping. + /// Returns 0 when the camera supports using a free value without stepping and + /// returns -1 when exposure compensation is not supported. Future getExposureOffsetStepSize(int cameraId) { throw UnimplementedError('getMinExposureOffset() is not implemented.'); } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index de4de97acff1..e139e2062db1 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.7.3 +version: 2.7.4 environment: sdk: ^3.1.0 diff --git a/packages/cross_file/CHANGELOG.md b/packages/cross_file/CHANGELOG.md index 52b11b97de35..2c4e4939615e 100644 --- a/packages/cross_file/CHANGELOG.md +++ b/packages/cross_file/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.4+1 + +* Removes a few deprecated API usages. + ## 0.3.4 * Updates to web code to package `web: ^0.5.0`. diff --git a/packages/cross_file/lib/src/types/html.dart b/packages/cross_file/lib/src/types/html.dart index a58dc35278b5..8bc5361bbfb2 100644 --- a/packages/cross_file/lib/src/types/html.dart +++ b/packages/cross_file/lib/src/types/html.dart @@ -8,7 +8,7 @@ import 'dart:js_interop'; import 'dart:typed_data'; import 'package:meta/meta.dart'; -import 'package:web/helpers.dart'; +import 'package:web/web.dart'; import '../web_helpers/web_helpers.dart'; import 'base.dart'; @@ -133,22 +133,26 @@ class XFile extends XFileBase { throw Exception('Safari cannot handle XFiles larger than 4GB.'); } - late XMLHttpRequest request; - try { - request = await HttpRequest.request(path, responseType: 'blob'); - } on ProgressEvent catch (e) { - if (e.type == 'error') { - throw Exception( - 'Could not load Blob from its URL. Has it been revoked?'); - } - rethrow; - } - - _browserBlob = request.response as Blob?; + final Completer blobCompleter = Completer(); - assert(_browserBlob != null, 'The Blob backing this XFile cannot be null!'); - - return _browserBlob!; + late XMLHttpRequest request; + request = XMLHttpRequest() + ..open('get', path, true) + ..responseType = 'blob' + ..onLoad.listen((ProgressEvent e) { + assert(request.response != null, + 'The Blob backing this XFile cannot be null!'); + blobCompleter.complete(request.response! as Blob); + }) + ..onError.listen((ProgressEvent e) { + if (e.type == 'error') { + blobCompleter.completeError(Exception( + 'Could not load Blob from its URL. Has it been revoked?')); + } + }) + ..send(); + + return blobCompleter.future; } @override diff --git a/packages/cross_file/lib/src/web_helpers/web_helpers.dart b/packages/cross_file/lib/src/web_helpers/web_helpers.dart index ec9a2e86e7d7..bd50fc989502 100644 --- a/packages/cross_file/lib/src/web_helpers/web_helpers.dart +++ b/packages/cross_file/lib/src/web_helpers/web_helpers.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:web/helpers.dart'; +import 'package:web/web.dart'; /// Create anchor element with download attribute HTMLAnchorElement createAnchorElement(String href, String? suggestedName) => @@ -20,11 +20,11 @@ void addElementToContainerAndClick(Element container, HTMLElement element) { /// Initializes a DOM container where elements can be injected. Element ensureInitialized(String id) { - Element? target = querySelector('#$id'); + Element? target = document.querySelector('#$id'); if (target == null) { final Element targetElement = document.createElement('flt-x-file')..id = id; - querySelector('body')!.appendChild(targetElement); + document.body!.appendChild(targetElement); target = targetElement; } return target; diff --git a/packages/cross_file/pubspec.yaml b/packages/cross_file/pubspec.yaml index b7b7f7af1088..cf8f9ca7d447 100644 --- a/packages/cross_file/pubspec.yaml +++ b/packages/cross_file/pubspec.yaml @@ -2,7 +2,7 @@ name: cross_file description: An abstraction to allow working with files across multiple platforms. repository: https://github.com/flutter/packages/tree/main/packages/cross_file issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+cross_file%22 -version: 0.3.4 +version: 0.3.4+1 environment: sdk: ^3.3.0 diff --git a/packages/cross_file/test/x_file_html_test.dart b/packages/cross_file/test/x_file_html_test.dart index 4b1dabd1583d..dedd8806f01a 100644 --- a/packages/cross_file/test/x_file_html_test.dart +++ b/packages/cross_file/test/x_file_html_test.dart @@ -11,7 +11,7 @@ import 'dart:typed_data'; import 'package:cross_file/cross_file.dart'; import 'package:test/test.dart'; -import 'package:web/helpers.dart' as html; +import 'package:web/web.dart' as html; const String expectedStringContents = 'Hello, world! I ❤ ñ! 空手'; final Uint8List bytes = Uint8List.fromList(utf8.encode(expectedStringContents)); @@ -95,7 +95,7 @@ void main() { await file.saveTo(''); final html.Element? container = - html.querySelector('#$crossFileDomElementId'); + html.document.querySelector('#$crossFileDomElementId'); expect(container, isNotNull); }); @@ -106,7 +106,7 @@ void main() { await file.saveTo('path'); final html.Element container = - html.querySelector('#$crossFileDomElementId')!; + html.document.querySelector('#$crossFileDomElementId')!; late html.HTMLAnchorElement element; for (int i = 0; i < container.childNodes.length; i++) { diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index e2dd2901aa8e..692d1da7589a 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.4+1 + +* Removes a few deprecated API usages. + ## 0.9.4 * Updates web code to package `web: ^0.5.0`. diff --git a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart index c4697a70a5d4..aa9dcdba187f 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart @@ -8,7 +8,7 @@ import 'package:file_selector_platform_interface/file_selector_platform_interfac import 'package:file_selector_web/src/dom_helper.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:web/helpers.dart'; +import 'package:web/web.dart'; void main() { group('dom_helper', () { @@ -41,7 +41,8 @@ void main() { setUp(() { domHelper = DomHelper(); - input = (createElementTag('input') as HTMLInputElement)..type = 'file'; + input = (document.createElement('input') as HTMLInputElement) + ..type = 'file'; }); group('getFiles', () { diff --git a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index f3d4c1ebf3e7..80376c5449fc 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -9,7 +9,7 @@ import 'package:file_selector_web/file_selector_web.dart'; import 'package:file_selector_web/src/dom_helper.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:web/helpers.dart'; +import 'package:web/web.dart'; void main() { group('FileSelectorWeb', () { diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 309f0ee432f1..c19748b92443 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -8,7 +8,7 @@ import 'dart:js_interop'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:flutter/foundation.dart' show visibleForTesting; import 'package:flutter/services.dart'; -import 'package:web/helpers.dart'; +import 'package:web/web.dart'; /// Class to manipulate the DOM with the intention of reading files from it. class DomHelper { diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index edc74e3064ea..2b4dc5cd7d9d 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_web description: Web platform implementation of file_selector repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.4 +version: 0.9.4+1 environment: sdk: ^3.3.0 diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index 854437f5d232..ef63d598bb83 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 2.9.4 -* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. +* Removes a few deprecated API usages. ## 2.9.3 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart index 7d9761a57602..e296ceb9d80d 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/html.dart @@ -27,7 +27,7 @@ class PickedFile extends PickedFileBase { Future get _bytes async { if (_initBytes != null) { - return Future.value(UnmodifiableUint8ListView(_initBytes!)); + return _initBytes.asUnmodifiableView(); } return http.readBytes(Uri.parse(path)); } diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 66b17ed51f47..b38945c6dac7 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,11 +4,11 @@ repository: https://github.com/flutter/packages/tree/main/packages/image_picker/ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.9.3 +version: 2.9.4 environment: - sdk: ^3.1.0 - flutter: ">=3.13.0" + sdk: ^3.3.0 + flutter: ">=3.19.0" dependencies: cross_file: ^0.3.1+1 diff --git a/packages/two_dimensional_scrollables/CHANGELOG.md b/packages/two_dimensional_scrollables/CHANGELOG.md index 52ea3b087a7f..64d1a0a6a552 100644 --- a/packages/two_dimensional_scrollables/CHANGELOG.md +++ b/packages/two_dimensional_scrollables/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.1 + +* Fixes a layout issue when pinned cells are merged. + ## 0.1.0 * [Breaking change] Adds support for merged cells in the TableView. diff --git a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart index 5d1575b1f5af..917881a61c29 100644 --- a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart +++ b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart @@ -801,7 +801,20 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { // | <--------- extent of merged cell ---------> | // Compute height and layout offset for merged rows. - mergedRowOffset = -verticalOffset.pixels + + final bool rowIsInPinnedColumn = _lastPinnedColumn != null && + vicinity.column <= _lastPinnedColumn!; + final bool rowIsPinned = + _lastPinnedRow != null && firstRow <= _lastPinnedRow!; + final double baseRowOffset = + switch ((rowIsInPinnedColumn, rowIsPinned)) { + // Both row and column are pinned at this cell, or just pinned row. + (true, true) || (false, true) => 0.0, + // Cell is within a pinned column + (true, false) => _pinnedRowsExtent - verticalOffset.pixels, + // Cell is within a pinned row, or no pinned portion. + (false, false) => -verticalOffset.pixels, + }; + mergedRowOffset = baseRowOffset + _rowMetrics[firstRow]!.leadingOffset + _rowMetrics[firstRow]!.configuration.padding.leading; mergedRowHeight = _rowMetrics[lastRow]!.trailingOffset - @@ -809,7 +822,20 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { _rowMetrics[lastRow]!.configuration.padding.trailing - _rowMetrics[firstRow]!.configuration.padding.leading; // Compute width and layout offset for merged columns. - mergedColumnOffset = -horizontalOffset.pixels + + final bool columnIsInPinnedRow = + _lastPinnedRow != null && vicinity.row <= _lastPinnedRow!; + final bool columnIsPinned = + _lastPinnedColumn != null && firstColumn <= _lastPinnedColumn!; + final double baseColumnOffset = + switch ((columnIsInPinnedRow, columnIsPinned)) { + // Both row and column are pinned at this cell, or just pinned column. + (true, true) || (false, true) => 0.0, + // Cell is within a pinned row. + (true, false) => _pinnedColumnsExtent - horizontalOffset.pixels, + // No pinned portion. + (false, false) => -horizontalOffset.pixels, + }; + mergedColumnOffset = baseColumnOffset + _columnMetrics[firstColumn]!.leadingOffset + _columnMetrics[firstColumn]!.configuration.padding.leading; mergedColumnWidth = _columnMetrics[lastColumn]!.trailingOffset - diff --git a/packages/two_dimensional_scrollables/pubspec.yaml b/packages/two_dimensional_scrollables/pubspec.yaml index e67277843dee..8d04d42f6455 100644 --- a/packages/two_dimensional_scrollables/pubspec.yaml +++ b/packages/two_dimensional_scrollables/pubspec.yaml @@ -1,6 +1,6 @@ name: two_dimensional_scrollables description: Widgets that scroll using the two dimensional scrolling foundation. -version: 0.1.0 +version: 0.1.1 repository: https://github.com/flutter/packages/tree/main/packages/two_dimensional_scrollables issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+two_dimensional_scrollables%22+ diff --git a/packages/two_dimensional_scrollables/test/table_view/table_test.dart b/packages/two_dimensional_scrollables/test/table_view/table_test.dart index 7d59ad8aa573..c24d1927405e 100644 --- a/packages/two_dimensional_scrollables/test/table_view/table_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/table_test.dart @@ -1730,6 +1730,482 @@ void main() { SystemMouseCursors.basic, ); }); + + group('Merged pinned cells layout', () { + // Regression tests for https://github.com/flutter/flutter/issues/143526 + // These tests all use the same collection of merged pinned cells in a + // variety of combinations. + final Map bothMerged = + { + TableVicinity.zero: (start: 0, span: 2), + const TableVicinity(row: 1, column: 0): (start: 0, span: 2), + const TableVicinity(row: 0, column: 1): (start: 0, span: 2), + const TableVicinity(row: 1, column: 1): (start: 0, span: 2), + }; + + final Map rowMerged = + { + const TableVicinity(row: 2, column: 0): (start: 2, span: 2), + const TableVicinity(row: 3, column: 0): (start: 2, span: 2), + const TableVicinity(row: 4, column: 1): (start: 4, span: 3), + const TableVicinity(row: 5, column: 1): (start: 4, span: 3), + const TableVicinity(row: 6, column: 1): (start: 4, span: 3), + }; + + final Map columnMerged = + { + const TableVicinity(row: 0, column: 2): (start: 2, span: 2), + const TableVicinity(row: 0, column: 3): (start: 2, span: 2), + const TableVicinity(row: 1, column: 4): (start: 4, span: 3), + const TableVicinity(row: 1, column: 5): (start: 4, span: 3), + const TableVicinity(row: 1, column: 6): (start: 4, span: 3), + }; + const TableSpan span = TableSpan(extent: FixedTableSpanExtent(75)); + + testWidgets('Normal axes', (WidgetTester tester) async { + final ScrollController verticalController = ScrollController(); + final ScrollController horizontalController = ScrollController(); + final TableView tableView = TableView.builder( + verticalDetails: ScrollableDetails.vertical( + controller: verticalController, + ), + horizontalDetails: ScrollableDetails.horizontal( + controller: horizontalController, + ), + columnCount: 20, + rowCount: 20, + pinnedRowCount: 2, + pinnedColumnCount: 2, + columnBuilder: (_) => span, + rowBuilder: (_) => span, + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + columnMergeStart: + bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start, + columnMergeSpan: + bothMerged[vicinity]?.span ?? columnMerged[vicinity]?.span, + rowMergeStart: + bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start, + rowMergeSpan: + bothMerged[vicinity]?.span ?? rowMerged[vicinity]?.span, + child: Text( + 'R${bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start ?? vicinity.row}:' + 'C${bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start ?? vicinity.column}', + ), + ); + }, + ); + await tester.pumpWidget(MaterialApp(home: tableView)); + await tester.pumpAndSettle(); + + expect(verticalController.position.pixels, 0.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(150.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(300.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 150.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 300.0, 75.0, 225.0), + ); + + verticalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(150.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(300.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 140.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 290.0, 75.0, 225.0), + ); + + horizontalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 10.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(140.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(290.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 140.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 290.0, 75.0, 225.0), + ); + }); + + testWidgets('Vertical reversed', (WidgetTester tester) async { + final ScrollController verticalController = ScrollController(); + final ScrollController horizontalController = ScrollController(); + final TableView tableView = TableView.builder( + verticalDetails: ScrollableDetails.vertical( + reverse: true, + controller: verticalController, + ), + horizontalDetails: ScrollableDetails.horizontal( + controller: horizontalController, + ), + columnCount: 20, + rowCount: 20, + pinnedRowCount: 2, + pinnedColumnCount: 2, + columnBuilder: (_) => span, + rowBuilder: (_) => span, + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + columnMergeStart: + bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start, + columnMergeSpan: + bothMerged[vicinity]?.span ?? columnMerged[vicinity]?.span, + rowMergeStart: + bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start, + rowMergeSpan: + bothMerged[vicinity]?.span ?? rowMerged[vicinity]?.span, + child: Text( + 'R${bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start ?? vicinity.row}:' + 'C${bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start ?? vicinity.column}', + ), + ); + }, + ); + await tester.pumpWidget(MaterialApp(home: tableView)); + await tester.pumpAndSettle(); + + expect(verticalController.position.pixels, 0.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(150.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(300.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 300.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 75.0, 75.0, 225.0), + ); + + verticalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(150.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(300.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 310.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 85.0, 75.0, 225.0), + ); + + horizontalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 10.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(0.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(140.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(290.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(0.0, 310.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(75.0, 85.0, 75.0, 225.0), + ); + }); + + testWidgets('Horizontal reversed', (WidgetTester tester) async { + final ScrollController verticalController = ScrollController(); + final ScrollController horizontalController = ScrollController(); + final TableView tableView = TableView.builder( + verticalDetails: ScrollableDetails.vertical( + controller: verticalController, + ), + horizontalDetails: ScrollableDetails.horizontal( + reverse: true, + controller: horizontalController, + ), + columnCount: 20, + rowCount: 20, + pinnedRowCount: 2, + pinnedColumnCount: 2, + columnBuilder: (_) => span, + rowBuilder: (_) => span, + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + columnMergeStart: + bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start, + columnMergeSpan: + bothMerged[vicinity]?.span ?? columnMerged[vicinity]?.span, + rowMergeStart: + bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start, + rowMergeSpan: + bothMerged[vicinity]?.span ?? rowMerged[vicinity]?.span, + child: Text( + 'R${bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start ?? vicinity.row}:' + 'C${bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start ?? vicinity.column}', + ), + ); + }, + ); + await tester.pumpWidget(MaterialApp(home: tableView)); + await tester.pumpAndSettle(); + + expect(verticalController.position.pixels, 0.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(500.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(275.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 150.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 300.0, 75.0, 225.0), + ); + + verticalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(500.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(275.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 140.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 290.0, 75.0, 225.0), + ); + + horizontalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 10.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 0.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(510.0, 0.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(285.0, 75.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 140.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 290.0, 75.0, 225.0), + ); + }); + + testWidgets('Both reversed', (WidgetTester tester) async { + final ScrollController verticalController = ScrollController(); + final ScrollController horizontalController = ScrollController(); + final TableView tableView = TableView.builder( + verticalDetails: ScrollableDetails.vertical( + reverse: true, + controller: verticalController, + ), + horizontalDetails: ScrollableDetails.horizontal( + reverse: true, + controller: horizontalController, + ), + columnCount: 20, + rowCount: 20, + pinnedRowCount: 2, + pinnedColumnCount: 2, + columnBuilder: (_) => span, + rowBuilder: (_) => span, + cellBuilder: (_, TableVicinity vicinity) { + return TableViewCell( + columnMergeStart: + bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start, + columnMergeSpan: + bothMerged[vicinity]?.span ?? columnMerged[vicinity]?.span, + rowMergeStart: + bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start, + rowMergeSpan: + bothMerged[vicinity]?.span ?? rowMerged[vicinity]?.span, + child: Text( + 'R${bothMerged[vicinity]?.start ?? rowMerged[vicinity]?.start ?? vicinity.row}:' + 'C${bothMerged[vicinity]?.start ?? columnMerged[vicinity]?.start ?? vicinity.column}', + ), + ); + }, + ); + await tester.pumpWidget(MaterialApp(home: tableView)); + await tester.pumpAndSettle(); + + expect(verticalController.position.pixels, 0.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(500.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(275.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 300.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 75.0, 75.0, 225.0), + ); + + verticalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 0.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(500.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(275.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 310.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 85.0, 75.0, 225.0), + ); + + horizontalController.jumpTo(10.0); + await tester.pumpAndSettle(); + expect(verticalController.position.pixels, 10.0); + expect(horizontalController.position.pixels, 10.0); + expect( + tester.getRect(find.text('R0:C0')), + const Rect.fromLTWH(650.0, 450.0, 150.0, 150.0), + ); + expect( + tester.getRect(find.text('R0:C2')), + const Rect.fromLTWH(510.0, 525.0, 150.0, 75.0), + ); + expect( + tester.getRect(find.text('R1:C4')), + const Rect.fromLTWH(285.0, 450.0, 225.0, 75.0), + ); + expect( + tester.getRect(find.text('R2:C0')), + const Rect.fromLTWH(725.0, 310.0, 75.0, 150.0), + ); + expect( + tester.getRect(find.text('R4:C1')), + const Rect.fromLTWH(650.0, 85.0, 75.0, 225.0), + ); + }); + }); }); } diff --git a/packages/web_benchmarks/CHANGELOG.md b/packages/web_benchmarks/CHANGELOG.md index c4b3cf125ad2..02e11be9976d 100644 --- a/packages/web_benchmarks/CHANGELOG.md +++ b/packages/web_benchmarks/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.1 + +* Removes a few deprecated API usages. + ## 1.2.0 * Updates to web code to package `web: ^0.5.0`. diff --git a/packages/web_benchmarks/lib/client.dart b/packages/web_benchmarks/lib/client.dart index d1c52d775fb8..d800e97a7589 100644 --- a/packages/web_benchmarks/lib/client.dart +++ b/packages/web_benchmarks/lib/client.dart @@ -318,7 +318,7 @@ class LocalBenchmarkServerClient { /// DevTools Protocol. Future startPerformanceTracing(String? benchmarkName) async { _checkNotManualMode(); - await HttpRequest.request( + await _requestXhr( '/start-performance-tracing?label=$benchmarkName', method: 'POST', mimeType: 'application/json', @@ -328,7 +328,7 @@ class LocalBenchmarkServerClient { /// Stops the performance tracing session started by [startPerformanceTracing]. Future stopPerformanceTracing() async { _checkNotManualMode(); - await HttpRequest.request( + await _requestXhr( '/stop-performance-tracing', method: 'POST', mimeType: 'application/json', @@ -356,7 +356,7 @@ class LocalBenchmarkServerClient { /// The server will halt the devicelab task and log the error. Future reportError(dynamic error, StackTrace stackTrace) async { _checkNotManualMode(); - await HttpRequest.request( + await _requestXhr( '/on-error', method: 'POST', mimeType: 'application/json', @@ -370,7 +370,7 @@ class LocalBenchmarkServerClient { /// Reports a message about the demo to the benchmark server. Future printToConsole(String report) async { _checkNotManualMode(); - await HttpRequest.request( + await _requestXhr( '/print-to-console', method: 'POST', mimeType: 'text/plain', @@ -384,7 +384,7 @@ class LocalBenchmarkServerClient { String url, { required String method, required String mimeType, - required String sendData, + String? sendData, }) { final Completer completer = Completer(); final XMLHttpRequest xhr = XMLHttpRequest(); @@ -394,7 +394,11 @@ class LocalBenchmarkServerClient { completer.complete(xhr); }); xhr.onError.listen(completer.completeError); - xhr.send(sendData.toJS); + if (sendData != null) { + xhr.send(sendData.toJS); + } else { + xhr.send(); + } return completer.future; } } diff --git a/packages/web_benchmarks/lib/src/recorder.dart b/packages/web_benchmarks/lib/src/recorder.dart index 7488c44c2c41..85d841f1f8cd 100644 --- a/packages/web_benchmarks/lib/src/recorder.dart +++ b/packages/web_benchmarks/lib/src/recorder.dart @@ -248,6 +248,7 @@ abstract class SceneBuilderRecorder extends Recorder { } }; PlatformDispatcher.instance.onDrawFrame = () { + final FlutterView? view = PlatformDispatcher.instance.implicitView; try { _profile.record('drawFrameDuration', () { final SceneBuilder sceneBuilder = SceneBuilder(); @@ -255,7 +256,9 @@ abstract class SceneBuilderRecorder extends Recorder { _profile.record('sceneBuildDuration', () { final Scene scene = sceneBuilder.build(); _profile.record('windowRenderDuration', () { - window.render(scene); + assert(view != null, + 'Cannot profile windowRenderDuration on a null View.'); + view!.render(scene); }, reported: false); }, reported: false); }, reported: true); diff --git a/packages/web_benchmarks/pubspec.yaml b/packages/web_benchmarks/pubspec.yaml index 584e69706ee3..af66a69c9088 100644 --- a/packages/web_benchmarks/pubspec.yaml +++ b/packages/web_benchmarks/pubspec.yaml @@ -2,7 +2,7 @@ name: web_benchmarks description: A benchmark harness for performance-testing Flutter apps in Chrome. repository: https://github.com/flutter/packages/tree/main/packages/web_benchmarks issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+web_benchmarks%22 -version: 1.2.0 +version: 1.2.1 environment: sdk: ^3.3.0 @@ -14,7 +14,6 @@ dependencies: sdk: flutter flutter_test: sdk: flutter - http: ^1.0.0 logging: ^1.0.2 meta: ^1.7.0 path: ^1.8.0