mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Bumps the Dart version to 3.8 across the repo (excluding engine/src/flutter/third_party) and applies formatting updates from Dart 3.8. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
143 lines
4.4 KiB
Dart
143 lines
4.4 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
/// On web, the context menu (aka toolbar) is provided by the browser.
|
|
const bool isContextMenuProvidedByPlatform = isBrowser;
|
|
|
|
// Returns the RenderEditable at the given index, or the first if not given.
|
|
RenderEditable findRenderEditable(WidgetTester tester, {int index = 0}) {
|
|
final RenderObject root = tester.renderObject(find.byType(EditableText).at(index));
|
|
expect(root, isNotNull);
|
|
|
|
late RenderEditable renderEditable;
|
|
void recursiveFinder(RenderObject child) {
|
|
if (child is RenderEditable) {
|
|
renderEditable = child;
|
|
return;
|
|
}
|
|
child.visitChildren(recursiveFinder);
|
|
}
|
|
|
|
root.visitChildren(recursiveFinder);
|
|
expect(renderEditable, isNotNull);
|
|
return renderEditable;
|
|
}
|
|
|
|
List<TextSelectionPoint> globalize(Iterable<TextSelectionPoint> points, RenderBox box) {
|
|
return points.map<TextSelectionPoint>((TextSelectionPoint point) {
|
|
return TextSelectionPoint(box.localToGlobal(point.point), point.direction);
|
|
}).toList();
|
|
}
|
|
|
|
Offset textOffsetToPosition(WidgetTester tester, int offset, {int index = 0}) {
|
|
final RenderEditable renderEditable = findRenderEditable(tester, index: index);
|
|
final List<TextSelectionPoint> endpoints = globalize(
|
|
renderEditable.getEndpointsForSelection(TextSelection.collapsed(offset: offset)),
|
|
renderEditable,
|
|
);
|
|
expect(endpoints.length, 1);
|
|
return endpoints[0].point + const Offset(kIsWeb ? 1.0 : 0.0, -2.0);
|
|
}
|
|
|
|
/// Mimic key press events by sending key down and key up events via the [tester].
|
|
Future<void> sendKeys(
|
|
WidgetTester tester,
|
|
List<LogicalKeyboardKey> keys, {
|
|
bool shift = false,
|
|
bool wordModifier = false,
|
|
bool lineModifier = false,
|
|
bool shortcutModifier = false,
|
|
required TargetPlatform targetPlatform,
|
|
}) async {
|
|
final String targetPlatformString = targetPlatform.toString();
|
|
final String platform = targetPlatformString
|
|
.substring(targetPlatformString.indexOf('.') + 1)
|
|
.toLowerCase();
|
|
if (shift) {
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
|
|
}
|
|
if (shortcutModifier) {
|
|
await tester.sendKeyDownEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.metaLeft
|
|
: LogicalKeyboardKey.controlLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
if (wordModifier) {
|
|
await tester.sendKeyDownEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.altLeft
|
|
: LogicalKeyboardKey.controlLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
if (lineModifier) {
|
|
await tester.sendKeyDownEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.metaLeft
|
|
: LogicalKeyboardKey.altLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
for (final LogicalKeyboardKey key in keys) {
|
|
await tester.sendKeyEvent(key, platform: platform);
|
|
await tester.pump();
|
|
}
|
|
if (lineModifier) {
|
|
await tester.sendKeyUpEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.metaLeft
|
|
: LogicalKeyboardKey.altLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
if (wordModifier) {
|
|
await tester.sendKeyUpEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.altLeft
|
|
: LogicalKeyboardKey.controlLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
if (shortcutModifier) {
|
|
await tester.sendKeyUpEvent(
|
|
platform == 'macos' || platform == 'ios'
|
|
? LogicalKeyboardKey.metaLeft
|
|
: LogicalKeyboardKey.controlLeft,
|
|
platform: platform,
|
|
);
|
|
}
|
|
if (shift) {
|
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
|
|
}
|
|
if (shift || wordModifier || lineModifier) {
|
|
await tester.pump();
|
|
}
|
|
}
|
|
|
|
// Simple controller that builds a WidgetSpan with 100 height.
|
|
class OverflowWidgetTextEditingController extends TextEditingController {
|
|
@override
|
|
TextSpan buildTextSpan({
|
|
required BuildContext context,
|
|
TextStyle? style,
|
|
required bool withComposing,
|
|
}) {
|
|
return TextSpan(
|
|
style: style,
|
|
children: <InlineSpan>[
|
|
const TextSpan(text: 'Hi'),
|
|
WidgetSpan(child: Container(color: Colors.redAccent, height: 100.0)),
|
|
],
|
|
);
|
|
}
|
|
}
|