mirror of
https://github.com/flutter/flutter
synced 2024-10-03 23:14:12 +00:00
Unify analysis options (#108462)
This commit is contained in:
parent
8a8ed75d3e
commit
10a7c9ba22
|
@ -99,7 +99,7 @@ linter:
|
|||
# - conditional_uri_does_not_exist # not yet tested
|
||||
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
|
||||
- control_flow_in_finally
|
||||
# - curly_braces_in_flow_control_structures # not required by flutter style, but developer-facing code should have this on
|
||||
- curly_braces_in_flow_control_structures
|
||||
- depend_on_referenced_packages
|
||||
- deprecated_consistency
|
||||
# - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib)
|
||||
|
|
|
@ -113,10 +113,11 @@ class ComplexLayoutState extends State<ComplexLayout> {
|
|||
key: const Key('complex-scroll'), // this key is used by the driver test
|
||||
controller: ScrollController(), // So that the scroll offset can be tracked
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (index.isEven)
|
||||
if (index.isEven) {
|
||||
return FancyImageItem(index, key: PageStorageKey<int>(index));
|
||||
else
|
||||
} else {
|
||||
return FancyGalleryItem(index, key: PageStorageKey<int>(index));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
@ -239,8 +239,9 @@ Map<String, dynamic> scrollSummary(
|
|||
//
|
||||
final double absJerk = (scrollOffset[i-1] + scrollOffset[i+1] - 2*scrollOffset[i]).abs();
|
||||
absJerkAvg += absJerk;
|
||||
if (absJerk > 0.5)
|
||||
if (absJerk > 0.5) {
|
||||
jankyCount += 1;
|
||||
}
|
||||
}
|
||||
// expect(lostFrame < 0.1 * frameTimestamp.length, true);
|
||||
absJerkAvg /= frameTimestamp.length - lostFrame;
|
||||
|
|
|
@ -18,8 +18,9 @@ void main() {
|
|||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
if (driver != null)
|
||||
if (driver != null) {
|
||||
driver.close();
|
||||
}
|
||||
});
|
||||
|
||||
Future<void> testScrollPerf(String listKey, String summaryName) async {
|
||||
|
|
|
@ -19,8 +19,9 @@ void main() {
|
|||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
if (driver != null)
|
||||
if (driver != null) {
|
||||
driver.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('initial tree creation', () async {
|
||||
|
@ -34,8 +35,9 @@ void main() {
|
|||
});
|
||||
|
||||
final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'SEMANTICS');
|
||||
if (semanticsEvents?.length != 2)
|
||||
if (semanticsEvents?.length != 2) {
|
||||
fail('Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents');
|
||||
}
|
||||
final Duration semanticsTreeCreation = Duration(microseconds: semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!);
|
||||
|
||||
final String jsonEncoded = json.encode(<String, dynamic>{'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds});
|
||||
|
|
|
@ -44,13 +44,16 @@ const int kExitCodeSuccess = 0;
|
|||
|
||||
final GetStackPointerCallback getStackPointer = () {
|
||||
// Makes sure we are running on an Android arm64 device.
|
||||
if (!io.Platform.isAndroid)
|
||||
if (!io.Platform.isAndroid) {
|
||||
throw 'This benchmark test can only be run on Android arm devices.';
|
||||
}
|
||||
final io.ProcessResult result = io.Process.runSync('getprop', <String>['ro.product.cpu.abi']);
|
||||
if (result.exitCode != 0)
|
||||
if (result.exitCode != 0) {
|
||||
throw 'Failed to retrieve CPU information.';
|
||||
if (!result.stdout.toString().contains('armeabi'))
|
||||
}
|
||||
if (!result.stdout.toString().contains('armeabi')) {
|
||||
throw 'This benchmark test can only be run on Android arm devices.';
|
||||
}
|
||||
|
||||
// Creates a block of memory to store the assembly code.
|
||||
final ffi.Pointer<ffi.Void> region = mmap(ffi.nullptr, kMemorySize, kProtRead | kProtWrite,
|
||||
|
|
|
@ -159,8 +159,9 @@ class _Tester {
|
|||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
await gesture.moveTo(location, timeStamp: currentTime);
|
||||
stopwatch.stop();
|
||||
if (onDataPoint != null)
|
||||
if (onDataPoint != null) {
|
||||
onDataPoint(stopwatch.elapsed);
|
||||
}
|
||||
await _UntilNextFrame.wait();
|
||||
}
|
||||
|
||||
|
|
|
@ -181,8 +181,9 @@ class _Tester {
|
|||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
await gesture.moveTo(location, timeStamp: currentTime);
|
||||
stopwatch.stop();
|
||||
if (onDataPoint != null)
|
||||
if (onDataPoint != null) {
|
||||
onDataPoint(stopwatch.elapsed);
|
||||
}
|
||||
await _UntilNextFrame.wait();
|
||||
}
|
||||
|
||||
|
|
|
@ -405,8 +405,9 @@ abstract class WidgetRecorder extends Recorder implements FrameRecorder {
|
|||
if (shouldContinue()) {
|
||||
PlatformDispatcher.instance.scheduleFrame();
|
||||
} else {
|
||||
for (final VoidCallback fn in _didStopCallbacks)
|
||||
for (final VoidCallback fn in _didStopCallbacks) {
|
||||
fn();
|
||||
}
|
||||
_runCompleter!.complete();
|
||||
}
|
||||
}
|
||||
|
@ -520,8 +521,9 @@ abstract class WidgetBuildRecorder extends Recorder implements FrameRecorder {
|
|||
showWidget = !showWidget;
|
||||
_hostState._setStateTrampoline();
|
||||
} else {
|
||||
for (final VoidCallback fn in _didStopCallbacks)
|
||||
for (final VoidCallback fn in _didStopCallbacks) {
|
||||
fn();
|
||||
}
|
||||
_runCompleter!.complete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,13 +39,14 @@ void main() {
|
|||
watch.stop();
|
||||
final int elapsed = watch.elapsedMicroseconds;
|
||||
final double averagePerIteration = elapsed / iteration;
|
||||
if (addResult)
|
||||
if (addResult) {
|
||||
printer.addResult(
|
||||
description: '$name ($listenerCount listeners)',
|
||||
value: averagePerIteration * _kScale,
|
||||
unit: 'ns per iteration',
|
||||
name: '$name$listenerCount',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,13 +66,14 @@ void main() {
|
|||
watch.stop();
|
||||
final int elapsed = watch.elapsedMicroseconds;
|
||||
final double averagePerIteration = elapsed / iteration;
|
||||
if (addResult)
|
||||
if (addResult) {
|
||||
printer.addResult(
|
||||
description: '$name ($listenerCount listeners)',
|
||||
value: averagePerIteration * _kScale,
|
||||
unit: 'ns per iteration',
|
||||
name: '$name$listenerCount',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,13 +109,14 @@ void main() {
|
|||
watch.stop();
|
||||
final int elapsed = watch.elapsedMicroseconds;
|
||||
final double averagePerIteration = elapsed / iteration;
|
||||
if (addResult)
|
||||
if (addResult) {
|
||||
printer.addResult(
|
||||
description: '$name ($listenerCount listeners)',
|
||||
value: averagePerIteration * _kScale,
|
||||
unit: 'ns per iteration',
|
||||
name: '$name$listenerCount',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,13 +159,14 @@ void main() {
|
|||
watch.stop();
|
||||
final int elapsed = watch.elapsedMicroseconds;
|
||||
final double averagePerIteration = elapsed / iteration;
|
||||
if (addResult)
|
||||
if (addResult) {
|
||||
printer.addResult(
|
||||
description: '$name ($listenerCount listeners)',
|
||||
value: averagePerIteration * _kScale,
|
||||
unit: 'ns per iteration',
|
||||
name: '$name$listenerCount',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,12 @@ void main() {
|
|||
watch.start();
|
||||
for (int i = 0; i < _kNumIters; i += 1) {
|
||||
for (final PointerEvent event in velocityEventData) {
|
||||
if (event is PointerDownEvent || event is PointerMoveEvent)
|
||||
if (event is PointerDownEvent || event is PointerMoveEvent) {
|
||||
tracker.addPosition(event.timeStamp, event.position);
|
||||
if (event is PointerUpEvent)
|
||||
}
|
||||
if (event is PointerUpEvent) {
|
||||
tracker.getVelocity();
|
||||
}
|
||||
}
|
||||
}
|
||||
watch.stop();
|
||||
|
|
|
@ -67,8 +67,9 @@ class StockArrow extends StatelessWidget {
|
|||
}
|
||||
|
||||
Color _colorForPercentChange(double percentChange) {
|
||||
if (percentChange > 0)
|
||||
if (percentChange > 0) {
|
||||
return Colors.green[_colorIndexForPercentChange(percentChange)]!;
|
||||
}
|
||||
return Colors.red[_colorIndexForPercentChange(percentChange)]!;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,8 +85,9 @@ class StockHomeState extends State<StockHome> {
|
|||
}
|
||||
|
||||
void _handleStockModeChange(StockMode? value) {
|
||||
if (widget.updater != null)
|
||||
if (widget.updater != null) {
|
||||
widget.updater(widget.configuration.copyWith(stockMode: value));
|
||||
}
|
||||
}
|
||||
|
||||
void _handleStockMenu(BuildContext context, _StockMenuItem value) {
|
||||
|
@ -239,8 +240,9 @@ class StockHomeState extends State<StockHome> {
|
|||
}
|
||||
|
||||
Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
|
||||
if (_searchQuery.text.isEmpty)
|
||||
if (_searchQuery.text.isEmpty) {
|
||||
return stocks;
|
||||
}
|
||||
final RegExp regexp = RegExp(_searchQuery.text, caseSensitive: false);
|
||||
return stocks.where((Stock stock) => stock.symbol.contains(regexp));
|
||||
}
|
||||
|
|
|
@ -32,8 +32,9 @@ class StockRow extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final String lastSale = '\$${stock.lastSale.toStringAsFixed(2)}';
|
||||
String changeInPrice = '${stock.percentChange.toStringAsFixed(2)}%';
|
||||
if (stock.percentChange > 0)
|
||||
if (stock.percentChange > 0) {
|
||||
changeInPrice = '+$changeInPrice';
|
||||
}
|
||||
return InkWell(
|
||||
key: ValueKey<String>(stock.symbol),
|
||||
onTap: _getHandler(onPressed),
|
||||
|
|
|
@ -93,8 +93,9 @@ class StockSettingsState extends State<StockSettings> {
|
|||
}
|
||||
|
||||
void sendUpdates(StockConfiguration value) {
|
||||
if (widget.updater != null)
|
||||
if (widget.updater != null) {
|
||||
widget.updater(value);
|
||||
}
|
||||
}
|
||||
|
||||
AppBar buildAppBar(BuildContext context) {
|
||||
|
|
|
@ -21,8 +21,9 @@ class _StockSymbolView extends StatelessWidget {
|
|||
assert(stock != null);
|
||||
final String lastSale = '\$${stock.lastSale.toStringAsFixed(2)}';
|
||||
String changeInPrice = '${stock.percentChange.toStringAsFixed(2)}%';
|
||||
if (stock.percentChange > 0)
|
||||
if (stock.percentChange > 0) {
|
||||
changeInPrice = '+$changeInPrice';
|
||||
}
|
||||
|
||||
final TextStyle headings = Theme.of(context).textTheme.bodyText1!;
|
||||
return Container(
|
||||
|
|
|
@ -9,8 +9,9 @@ import 'package:stocks/stock_data.dart' as stock_data;
|
|||
|
||||
Element? findElementOfExactWidgetTypeGoingDown(Element node, Type targetType) {
|
||||
void walker(Element child) {
|
||||
if (child.widget.runtimeType == targetType)
|
||||
if (child.widget.runtimeType == targetType) {
|
||||
throw child;
|
||||
}
|
||||
child.visitChildElements(walker);
|
||||
}
|
||||
try {
|
||||
|
|
|
@ -460,12 +460,14 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
|
|||
for (int lineNumber in linesWithDeprecations) {
|
||||
try {
|
||||
final RegExpMatch? startMatch = _deprecationStartPattern.firstMatch(lines[lineNumber]);
|
||||
if (startMatch == null)
|
||||
if (startMatch == null) {
|
||||
throw 'Deprecation notice does not match required pattern.';
|
||||
}
|
||||
final String indent = startMatch.namedGroup('indent')!;
|
||||
lineNumber += 1;
|
||||
if (lineNumber >= lines.length)
|
||||
if (lineNumber >= lines.length) {
|
||||
throw 'Incomplete deprecation notice.';
|
||||
}
|
||||
RegExpMatch? versionMatch;
|
||||
String? message;
|
||||
do {
|
||||
|
@ -477,17 +479,20 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
|
|||
}
|
||||
throw 'Deprecation notice does not match required pattern.$possibleReason';
|
||||
}
|
||||
if (!lines[lineNumber].startsWith("$indent '"))
|
||||
if (!lines[lineNumber].startsWith("$indent '")) {
|
||||
throw 'Unexpected deprecation notice indent.';
|
||||
}
|
||||
if (message == null) {
|
||||
message = messageMatch.namedGroup('message');
|
||||
final String firstChar = String.fromCharCode(message!.runes.first);
|
||||
if (firstChar.toUpperCase() != firstChar)
|
||||
if (firstChar.toUpperCase() != firstChar) {
|
||||
throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo';
|
||||
}
|
||||
}
|
||||
lineNumber += 1;
|
||||
if (lineNumber >= lines.length)
|
||||
if (lineNumber >= lines.length) {
|
||||
throw 'Incomplete deprecation notice.';
|
||||
}
|
||||
versionMatch = _deprecationVersionPattern.firstMatch(lines[lineNumber]);
|
||||
} while (versionMatch == null);
|
||||
final int major = int.parse(versionMatch.namedGroup('major')!);
|
||||
|
@ -497,20 +502,26 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
|
|||
// There was a beta release that was mistakenly labeled 3.1.0 without a build.
|
||||
final bool specialBeta = major == 3 && minor == 1 && patch == 0;
|
||||
if (!specialBeta && (major > 1 || (major == 1 && minor >= 20))) {
|
||||
if (!hasBuild)
|
||||
if (!hasBuild) {
|
||||
throw 'Deprecation notice does not accurately indicate a beta branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest beta build version number.';
|
||||
}
|
||||
}
|
||||
if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?'))
|
||||
if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?')) {
|
||||
throw 'Deprecation notice should be a grammatically correct sentence and end with a period.';
|
||||
if (!lines[lineNumber].startsWith("$indent '"))
|
||||
}
|
||||
if (!lines[lineNumber].startsWith("$indent '")) {
|
||||
throw 'Unexpected deprecation notice indent.';
|
||||
}
|
||||
lineNumber += 1;
|
||||
if (lineNumber >= lines.length)
|
||||
if (lineNumber >= lines.length) {
|
||||
throw 'Incomplete deprecation notice.';
|
||||
if (!lines[lineNumber].contains(_deprecationEndPattern))
|
||||
}
|
||||
if (!lines[lineNumber].contains(_deprecationEndPattern)) {
|
||||
throw 'End of deprecation notice does not match required pattern.';
|
||||
if (!lines[lineNumber].startsWith('$indent)'))
|
||||
}
|
||||
if (!lines[lineNumber].startsWith('$indent)')) {
|
||||
throw 'Unexpected deprecation notice indent.';
|
||||
}
|
||||
} catch (error) {
|
||||
errors.add('${file.path}:${lineNumber + 1}: $error');
|
||||
}
|
||||
|
@ -569,10 +580,12 @@ Future<int> _verifyNoMissingLicenseForExtension(
|
|||
final List<String> errors = <String>[];
|
||||
await for (final File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) {
|
||||
final String contents = file.readAsStringSync().replaceAll('\r\n', '\n');
|
||||
if (contents.isEmpty)
|
||||
if (contents.isEmpty) {
|
||||
continue; // let's not go down the /bin/true rabbit hole
|
||||
if (!contents.startsWith(RegExp(header + licensePattern)))
|
||||
}
|
||||
if (!contents.startsWith(RegExp(header + licensePattern))) {
|
||||
errors.add(file.path);
|
||||
}
|
||||
}
|
||||
// Fail if any errors
|
||||
if (errors.isNotEmpty) {
|
||||
|
@ -679,8 +692,9 @@ Future<void> verifyNoTestImports(String workingDirectory) async {
|
|||
for (final File file in dartFiles) {
|
||||
for (final String line in file.readAsLinesSync()) {
|
||||
final Match? match = _testImportPattern.firstMatch(line);
|
||||
if (match != null && !_exemptTestImports.contains(match.group(2)))
|
||||
if (match != null && !_exemptTestImports.contains(match.group(2))) {
|
||||
errors.add(file.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fail if any errors
|
||||
|
@ -733,8 +747,9 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async {
|
|||
|
||||
for (final String key in dependencyMap.keys) {
|
||||
for (final String dependency in dependencyMap[key]!) {
|
||||
if (dependencyMap[dependency] != null)
|
||||
if (dependencyMap[dependency] != null) {
|
||||
continue;
|
||||
}
|
||||
// Sanity check before performing _deepSearch, to ensure there's no rogue
|
||||
// dependencies.
|
||||
final String validFilenames = dependencyMap.keys.map((String name) => '$name.dart').join(', ');
|
||||
|
@ -931,8 +946,9 @@ Future<void> verifyNoRuntimeTypeInToString(String workingDirectory) async {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (problems.isNotEmpty)
|
||||
if (problems.isNotEmpty) {
|
||||
exitWithError(problems);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatches = 4000 }) async {
|
||||
|
@ -956,11 +972,13 @@ Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatche
|
|||
problems.add('${file.path}:${index + 1}: trailing U+0009 tab character');
|
||||
}
|
||||
}
|
||||
if (lines.isNotEmpty && lines.last == '')
|
||||
if (lines.isNotEmpty && lines.last == '') {
|
||||
problems.add('${file.path}:${lines.length}: trailing blank line');
|
||||
}
|
||||
}
|
||||
if (problems.isNotEmpty)
|
||||
if (problems.isNotEmpty) {
|
||||
exitWithError(problems);
|
||||
}
|
||||
}
|
||||
|
||||
String _bullets(String value) => ' * $value';
|
||||
|
@ -984,8 +1002,9 @@ Future<void> verifyIssueLinks(String workingDirectory) async {
|
|||
final Set<String> suggestions = <String>{};
|
||||
final List<File> files = await _gitFiles(workingDirectory);
|
||||
for (final File file in files) {
|
||||
if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart')
|
||||
if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart') {
|
||||
continue; // Skip tests, they're not public-facing.
|
||||
}
|
||||
final Uint8List bytes = file.readAsBytesSync();
|
||||
// We allow invalid UTF-8 here so that binaries don't trip us up.
|
||||
// There's a separate test in this file that verifies that all text
|
||||
|
@ -1087,8 +1106,9 @@ class Hash256 {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is Hash256
|
||||
&& other.a == a
|
||||
&& other.b == b
|
||||
|
@ -1481,8 +1501,9 @@ Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBin
|
|||
utf8.decode(bytes);
|
||||
} on FormatException catch (error) {
|
||||
final Digest digest = sha256.convert(bytes);
|
||||
if (!legacyBinaries.contains(Hash256.fromDigest(digest)))
|
||||
if (!legacyBinaries.contains(Hash256.fromDigest(digest))) {
|
||||
problems.add('${file.path}:${error.offset}: file is not valid UTF-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (problems.isNotEmpty) {
|
||||
|
@ -1506,11 +1527,13 @@ Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBin
|
|||
bool _listEquals<T>(List<T> a, List<T> b) {
|
||||
assert(a != null);
|
||||
assert(b != null);
|
||||
if (a.length != b.length)
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
for (int index = 0; index < a.length; index += 1) {
|
||||
if (a[index] != b[index])
|
||||
if (a[index] != b[index]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1550,38 +1573,51 @@ Stream<File> _allFiles(String workingDirectory, String? extension, { required in
|
|||
while (pending.isNotEmpty) {
|
||||
final FileSystemEntity entity = pending.first;
|
||||
pending.remove(entity);
|
||||
if (path.extension(entity.path) == '.tmpl')
|
||||
if (path.extension(entity.path) == '.tmpl') {
|
||||
continue;
|
||||
}
|
||||
if (entity is File) {
|
||||
if (!gitFileNamesSet.contains(path.canonicalize(entity.absolute.path)))
|
||||
if (!gitFileNamesSet.contains(path.canonicalize(entity.absolute.path))) {
|
||||
continue;
|
||||
if (_isGeneratedPluginRegistrant(entity))
|
||||
}
|
||||
if (_isGeneratedPluginRegistrant(entity)) {
|
||||
continue;
|
||||
if (path.basename(entity.path) == 'flutter_export_environment.sh')
|
||||
}
|
||||
if (path.basename(entity.path) == 'flutter_export_environment.sh') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == 'gradlew.bat')
|
||||
}
|
||||
if (path.basename(entity.path) == 'gradlew.bat') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.DS_Store')
|
||||
}
|
||||
if (path.basename(entity.path) == '.DS_Store') {
|
||||
continue;
|
||||
}
|
||||
if (extension == null || path.extension(entity.path) == '.$extension') {
|
||||
matches += 1;
|
||||
yield entity;
|
||||
}
|
||||
} else if (entity is Directory) {
|
||||
if (File(path.join(entity.path, '.dartignore')).existsSync())
|
||||
if (File(path.join(entity.path, '.dartignore')).existsSync()) {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.git')
|
||||
}
|
||||
if (path.basename(entity.path) == '.git') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.idea')
|
||||
}
|
||||
if (path.basename(entity.path) == '.idea') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.gradle')
|
||||
}
|
||||
if (path.basename(entity.path) == '.gradle') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.dart_tool')
|
||||
}
|
||||
if (path.basename(entity.path) == '.dart_tool') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == '.idea')
|
||||
}
|
||||
if (path.basename(entity.path) == '.idea') {
|
||||
continue;
|
||||
if (path.basename(entity.path) == 'build')
|
||||
}
|
||||
if (path.basename(entity.path) == 'build') {
|
||||
continue;
|
||||
}
|
||||
pending.addAll(entity.listSync());
|
||||
}
|
||||
}
|
||||
|
@ -1830,8 +1866,9 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
|
|||
final Set<String> result = <String>{};
|
||||
for (final String line in file.readAsLinesSync()) {
|
||||
Match? match = _importPattern.firstMatch(line);
|
||||
if (match != null)
|
||||
if (match != null) {
|
||||
result.add(match.group(2)!);
|
||||
}
|
||||
if (checkForMeta) {
|
||||
match = _importMetaPattern.firstMatch(line);
|
||||
if (match != null) {
|
||||
|
@ -1852,14 +1889,17 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
|
|||
}
|
||||
|
||||
List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) {
|
||||
if (map[start] == null)
|
||||
if (map[start] == null) {
|
||||
return null; // We catch these separately.
|
||||
}
|
||||
|
||||
for (final T key in map[start]!) {
|
||||
if (key == start)
|
||||
if (key == start) {
|
||||
continue; // we catch these separately
|
||||
if (seen != null && seen.contains(key))
|
||||
}
|
||||
if (seen != null && seen.contains(key)) {
|
||||
return <T>[start, key];
|
||||
}
|
||||
final List<T>? result = _deepSearch<T>(
|
||||
map,
|
||||
key,
|
||||
|
@ -1874,8 +1914,9 @@ List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) {
|
|||
// For example a->b->a, rather than c->a->b->a.
|
||||
// Since we visit every node, we know the shortest chains are those
|
||||
// that start and end on the loop.
|
||||
if (result.first == result.last)
|
||||
if (result.first == result.last) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -396,12 +396,14 @@ class _SnippetChecker {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!silent)
|
||||
if (!silent) {
|
||||
print('Found ${sections.length} snippet code blocks');
|
||||
}
|
||||
for (final _Section section in sections) {
|
||||
final String path = _writeSection(section).path;
|
||||
if (sectionMap != null)
|
||||
if (sectionMap != null) {
|
||||
sectionMap[path] = section;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,8 +450,9 @@ class _SnippetChecker {
|
|||
|
||||
/// Invokes the analyzer on the given [directory] and returns the stdout.
|
||||
int _runAnalyzer(Directory directory, {bool silent = true, required List<String> output}) {
|
||||
if (!silent)
|
||||
if (!silent) {
|
||||
print('Starting analysis of code snippets.');
|
||||
}
|
||||
_createConfigurationFiles(directory);
|
||||
final ProcessResult result = Process.runSync(
|
||||
_flutter,
|
||||
|
@ -598,8 +601,9 @@ class _SnippetChecker {
|
|||
exitCode = 0;
|
||||
}
|
||||
if (exitCode == 0) {
|
||||
if (!silent)
|
||||
if (!silent) {
|
||||
print('No analysis errors in snippets!');
|
||||
}
|
||||
assert(analysisErrors.isEmpty);
|
||||
}
|
||||
return _AnalysisResult(exitCode, analysisErrors);
|
||||
|
@ -633,17 +637,19 @@ class _SnippetChecker {
|
|||
// Each section of the dart code that is either split by a blank line, or with '// ...' is
|
||||
// treated as a separate code block.
|
||||
if (block[index] == '' || block[index] == '// ...') {
|
||||
if (subline == null)
|
||||
if (subline == null) {
|
||||
throw _SnippetCheckerException('${_Line(filename: line.filename, line: line.line + index, indent: line.indent)}: '
|
||||
'Unexpected blank line or "// ..." line near start of subblock in snippet code.');
|
||||
}
|
||||
subblocks += 1;
|
||||
subsections.add(_processBlock(subline, buffer));
|
||||
buffer.clear();
|
||||
assert(buffer.isEmpty);
|
||||
subline = null;
|
||||
} else if (block[index].startsWith('// ')) {
|
||||
if (buffer.length > 1) // don't include leading comments
|
||||
if (buffer.length > 1) {
|
||||
buffer.add('/${block[index]}'); // so that it doesn't start with "// " and get caught in this again
|
||||
}
|
||||
} else {
|
||||
subline ??= _Line(
|
||||
code: block[index],
|
||||
|
|
|
@ -133,10 +133,12 @@ class FlutterCompactFormatter {
|
|||
originalResult.errorMessage = error;
|
||||
originalResult.stackTrace = stackTrace;
|
||||
} else {
|
||||
if (error != null)
|
||||
if (error != null) {
|
||||
stderr.writeln(error);
|
||||
if (stackTrace != null)
|
||||
}
|
||||
if (stackTrace != null) {
|
||||
stderr.writeln(stackTrace);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'print':
|
||||
|
|
|
@ -39,12 +39,15 @@ final String engineVersionFile = path.join(flutterRoot, 'bin', 'internal', 'engi
|
|||
final String flutterPluginsVersionFile = path.join(flutterRoot, 'bin', 'internal', 'flutter_plugins.version');
|
||||
|
||||
String get platformFolderName {
|
||||
if (Platform.isWindows)
|
||||
if (Platform.isWindows) {
|
||||
return 'windows-x64';
|
||||
if (Platform.isMacOS)
|
||||
}
|
||||
if (Platform.isMacOS) {
|
||||
return 'darwin-x64';
|
||||
if (Platform.isLinux)
|
||||
}
|
||||
if (Platform.isLinux) {
|
||||
return 'linux-x64';
|
||||
}
|
||||
throw UnsupportedError('The platform ${Platform.operatingSystem} is not supported by this script.');
|
||||
}
|
||||
final String flutterTester = path.join(flutterRoot, 'bin', 'cache', 'artifacts', 'engine', platformFolderName, 'flutter_tester$exe');
|
||||
|
@ -187,8 +190,9 @@ Future<void> main(List<String> args) async {
|
|||
}
|
||||
}
|
||||
flutterTestArgs.removeWhere((String arg) => removeArgs.contains(arg));
|
||||
if (Platform.environment.containsKey(CIRRUS_TASK_NAME))
|
||||
if (Platform.environment.containsKey(CIRRUS_TASK_NAME)) {
|
||||
print('Running task: ${Platform.environment[CIRRUS_TASK_NAME]}');
|
||||
}
|
||||
print('═' * 80);
|
||||
await selectShard(<String, ShardRunner>{
|
||||
'add_to_app_life_cycle_tests': _runAddToAppLifeCycleTests,
|
||||
|
@ -327,8 +331,9 @@ Future<void> _runTestHarnessTests() async {
|
|||
|
||||
// Verify that we correctly generated the version file.
|
||||
final String? versionError = await verifyVersion(File(path.join(flutterRoot, 'version')));
|
||||
if (versionError != null)
|
||||
if (versionError != null) {
|
||||
exitWithError(<String>[versionError]);
|
||||
}
|
||||
}
|
||||
|
||||
final String _toolsPath = path.join(flutterRoot, 'packages', 'flutter_tools');
|
||||
|
@ -1748,8 +1753,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
|
|||
];
|
||||
|
||||
final bool shouldProcessOutput = useFlutterTestFormatter && !expectFailure && !options.contains('--coverage');
|
||||
if (shouldProcessOutput)
|
||||
if (shouldProcessOutput) {
|
||||
args.add('--machine');
|
||||
}
|
||||
|
||||
if (script != null) {
|
||||
final String fullScriptPath = path.join(workingDirectory, script);
|
||||
|
@ -1757,8 +1763,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
|
|||
print('${red}Could not find test$reset: $green$fullScriptPath$reset');
|
||||
print('Working directory: $cyan$workingDirectory$reset');
|
||||
print('Script: $green$script$reset');
|
||||
if (!printOutput)
|
||||
if (!printOutput) {
|
||||
print('This is one of the tests that does not normally print output.');
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
args.add(script);
|
||||
|
@ -1782,8 +1789,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
|
|||
|
||||
if (outputChecker != null) {
|
||||
final String? message = outputChecker(result);
|
||||
if (message != null)
|
||||
if (message != null) {
|
||||
exitWithError(<String>[message]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1862,12 +1870,15 @@ Future<String?> verifyVersion(File file) async {
|
|||
final RegExp pattern = RegExp(
|
||||
r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre(\.\d+)?)?$');
|
||||
final String version = await file.readAsString();
|
||||
if (!file.existsSync())
|
||||
if (!file.existsSync()) {
|
||||
return 'The version logic failed to create the Flutter version file.';
|
||||
if (version == '0.0.0-unknown')
|
||||
}
|
||||
if (version == '0.0.0-unknown') {
|
||||
return 'The version logic failed to determine the Flutter version.';
|
||||
if (!version.contains(pattern))
|
||||
}
|
||||
if (!version.contains(pattern)) {
|
||||
return 'The version logic generated an invalid version string: "$version".';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,9 @@ String get clock {
|
|||
String prettyPrintDuration(Duration duration) {
|
||||
String result = '';
|
||||
final int minutes = duration.inMinutes;
|
||||
if (minutes > 0)
|
||||
if (minutes > 0) {
|
||||
result += '${minutes}min ';
|
||||
}
|
||||
final int seconds = duration.inSeconds - minutes * 60;
|
||||
final int milliseconds = duration.inMilliseconds - (seconds * 1000 + minutes * 60 * 1000);
|
||||
result += '$seconds.${milliseconds.toString().padLeft(3, "0")}s';
|
||||
|
|
|
@ -8,6 +8,5 @@ analyzer:
|
|||
linter:
|
||||
rules:
|
||||
avoid_catches_without_on_clauses: true
|
||||
curly_braces_in_flow_control_structures: true
|
||||
prefer_relative_imports: true
|
||||
unawaited_futures: true
|
||||
|
|
|
@ -31,42 +31,54 @@ class CustomerTest {
|
|||
test.add(line.substring(5));
|
||||
} else if (line.startsWith('test.windows=')) {
|
||||
hasTests = true;
|
||||
if (Platform.isWindows)
|
||||
if (Platform.isWindows) {
|
||||
test.add(line.substring(13));
|
||||
}
|
||||
} else if (line.startsWith('test.macos=')) {
|
||||
hasTests = true;
|
||||
if (Platform.isMacOS)
|
||||
if (Platform.isMacOS) {
|
||||
test.add(line.substring(11));
|
||||
}
|
||||
} else if (line.startsWith('test.linux=')) {
|
||||
hasTests = true;
|
||||
if (Platform.isLinux)
|
||||
if (Platform.isLinux) {
|
||||
test.add(line.substring(11));
|
||||
}
|
||||
} else if (line.startsWith('test.posix=')) {
|
||||
hasTests = true;
|
||||
if (Platform.isLinux || Platform.isMacOS)
|
||||
if (Platform.isLinux || Platform.isMacOS) {
|
||||
test.add(line.substring(11));
|
||||
}
|
||||
} else {
|
||||
throw FormatException('${errorPrefix}Unexpected directive:\n$line');
|
||||
}
|
||||
}
|
||||
if (contacts.isEmpty)
|
||||
if (contacts.isEmpty) {
|
||||
throw FormatException('${errorPrefix}No contacts specified. At least one contact e-mail address must be specified.');
|
||||
for (final String email in contacts) {
|
||||
if (!email.contains(_email) || email.endsWith('@example.com'))
|
||||
throw FormatException('${errorPrefix}The following e-mail address appears to be an invalid e-mail address: $email');
|
||||
}
|
||||
if (fetch.isEmpty)
|
||||
for (final String email in contacts) {
|
||||
if (!email.contains(_email) || email.endsWith('@example.com')) {
|
||||
throw FormatException('${errorPrefix}The following e-mail address appears to be an invalid e-mail address: $email');
|
||||
}
|
||||
}
|
||||
if (fetch.isEmpty) {
|
||||
throw FormatException('${errorPrefix}No "fetch" directives specified. Two lines are expected: "git clone https://github.com/USERNAME/REPOSITORY.git tests" and "git -C tests checkout HASH".');
|
||||
if (fetch.length < 2)
|
||||
}
|
||||
if (fetch.length < 2) {
|
||||
throw FormatException('${errorPrefix}Only one "fetch" directive specified. Two lines are expected: "git clone https://github.com/USERNAME/REPOSITORY.git tests" and "git -C tests checkout HASH".');
|
||||
if (!fetch[0].contains(_fetch1))
|
||||
}
|
||||
if (!fetch[0].contains(_fetch1)) {
|
||||
throw FormatException('${errorPrefix}First "fetch" directive does not match expected pattern (expected "git clone https://github.com/USERNAME/REPOSITORY.git tests").');
|
||||
if (!fetch[1].contains(_fetch2))
|
||||
}
|
||||
if (!fetch[1].contains(_fetch2)) {
|
||||
throw FormatException('${errorPrefix}Second "fetch" directive does not match expected pattern (expected "git -C tests checkout HASH").');
|
||||
if (update.isEmpty)
|
||||
}
|
||||
if (update.isEmpty) {
|
||||
throw FormatException('${errorPrefix}No "update" directives specified. At least one directory must be specified. (It can be "." to just upgrade the root of the repository.)');
|
||||
if (!hasTests)
|
||||
}
|
||||
if (!hasTests) {
|
||||
throw FormatException('${errorPrefix}No "test" directives specified. At least one command must be specified to run tests.');
|
||||
}
|
||||
return CustomerTest._(
|
||||
List<String>.unmodifiable(contacts),
|
||||
List<String>.unmodifiable(fetch),
|
||||
|
|
|
@ -17,8 +17,9 @@ Future<bool> runTests({
|
|||
int shardIndex = 0,
|
||||
required List<File> files,
|
||||
}) async {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Starting run_tests.dart...');
|
||||
}
|
||||
|
||||
// Best attempt at evenly splitting tests among the shards
|
||||
final List<File> shardedFiles = <File>[];
|
||||
|
@ -46,18 +47,21 @@ Future<bool> runTests({
|
|||
} else {
|
||||
print('Tests:');
|
||||
}
|
||||
for (final File file in shardedFiles)
|
||||
for (final File file in shardedFiles) {
|
||||
print(file.path);
|
||||
}
|
||||
}
|
||||
print('');
|
||||
|
||||
for (final File file in shardedFiles) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Processing ${file.path}...');
|
||||
}
|
||||
|
||||
void printHeader() {
|
||||
if (!verbose)
|
||||
if (!verbose) {
|
||||
print('Processing ${file.path}...');
|
||||
}
|
||||
}
|
||||
|
||||
void failure(String message) {
|
||||
|
@ -82,8 +86,9 @@ Future<bool> runTests({
|
|||
bool success = true;
|
||||
|
||||
final Directory checkout = Directory.systemTemp.createTempSync('flutter_customer_testing.${path.basenameWithoutExtension(file.path)}.');
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Created temporary directory: ${checkout.path}');
|
||||
}
|
||||
try {
|
||||
assert(instructions.fetch.isNotEmpty);
|
||||
for (final String fetchCommand in instructions.fetch) {
|
||||
|
@ -105,8 +110,9 @@ Future<bool> runTests({
|
|||
final Directory customerRepo = Directory(path.join(checkout.path, 'tests'));
|
||||
for (final Directory updateDirectory in instructions.update) {
|
||||
final Directory resolvedUpdateDirectory = Directory(path.join(customerRepo.path, updateDirectory.path));
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Updating code in ${resolvedUpdateDirectory.path}...');
|
||||
}
|
||||
if (!File(path.join(resolvedUpdateDirectory.path, 'pubspec.yaml')).existsSync()) {
|
||||
failure('The directory ${updateDirectory.path}, which was specified as an update directory, does not contain a "pubspec.yaml" file.');
|
||||
success = false;
|
||||
|
@ -124,11 +130,13 @@ Future<bool> runTests({
|
|||
}
|
||||
}
|
||||
if (success) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Running tests...');
|
||||
}
|
||||
for (int iteration = 0; iteration < repeat; iteration += 1) {
|
||||
if (verbose && repeat > 1)
|
||||
if (verbose && repeat > 1) {
|
||||
print('Round ${iteration + 1} of $repeat.');
|
||||
}
|
||||
for (final String testCommand in instructions.tests) {
|
||||
testCount += 1;
|
||||
success = await shell(testCommand, customerRepo, verbose: verbose, failedCallback: printHeader);
|
||||
|
@ -138,13 +146,15 @@ Future<bool> runTests({
|
|||
}
|
||||
}
|
||||
}
|
||||
if (verbose && success)
|
||||
if (verbose && success) {
|
||||
print('Tests finished.');
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('Deleting temporary directory...');
|
||||
}
|
||||
try {
|
||||
checkout.deleteSync(recursive: true);
|
||||
} on FileSystemException {
|
||||
|
@ -155,8 +165,9 @@ Future<bool> runTests({
|
|||
final String s = instructions.contacts.length == 1 ? '' : 's';
|
||||
print('Contact$s: ${instructions.contacts.join(", ")}');
|
||||
}
|
||||
if (verbose || !success)
|
||||
if (verbose || !success) {
|
||||
print('');
|
||||
}
|
||||
}
|
||||
if (failures > 0) {
|
||||
final String s = failures == 1 ? '' : 's';
|
||||
|
@ -170,8 +181,9 @@ Future<bool> runTests({
|
|||
final RegExp _spaces = RegExp(r' +');
|
||||
|
||||
Future<bool> shell(String command, Directory directory, { bool verbose = false, bool silentFailure = false, void Function()? failedCallback }) async {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
print('>> $command');
|
||||
}
|
||||
Process process;
|
||||
if (Platform.isWindows) {
|
||||
process = await Process.start('CMD.EXE', <String>['/S', '/C', command], workingDirectory: directory.path);
|
||||
|
@ -183,11 +195,13 @@ Future<bool> shell(String command, Directory directory, { bool verbose = false,
|
|||
utf8.decoder.bind(process.stdout).transform(const LineSplitter()).listen(verbose ? printLog : output.add);
|
||||
utf8.decoder.bind(process.stderr).transform(const LineSplitter()).listen(verbose ? printLog : output.add);
|
||||
final bool success = await process.exitCode == 0;
|
||||
if (success || silentFailure)
|
||||
if (success || silentFailure) {
|
||||
return success;
|
||||
}
|
||||
if (!verbose) {
|
||||
if (failedCallback != null)
|
||||
if (failedCallback != null) {
|
||||
failedCallback();
|
||||
}
|
||||
print('>> $command');
|
||||
output.forEach(printLog);
|
||||
}
|
||||
|
|
|
@ -92,8 +92,9 @@ Future<bool> run(List<String> arguments) async {
|
|||
if (help || repeat == null || files.isEmpty || numberShards == null || numberShards <= 0 || shardIndex == null || shardIndex < 0) {
|
||||
printHelp();
|
||||
if (verbose) {
|
||||
if (repeat == null)
|
||||
if (repeat == null) {
|
||||
print('Error: Could not parse repeat count ("${parsedArguments['repeat']}")');
|
||||
}
|
||||
if (numberShards == null) {
|
||||
print('Error: Could not parse shards count ("${parsedArguments['shards']}")');
|
||||
} else if (numberShards < 1) {
|
||||
|
@ -121,8 +122,9 @@ Future<bool> run(List<String> arguments) async {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (files.length < numberShards)
|
||||
if (files.length < numberShards) {
|
||||
print('Warning: There are more shards than tests. Some shards will not run any tests.');
|
||||
}
|
||||
|
||||
return runTests(
|
||||
repeat: repeat,
|
||||
|
|
|
@ -19,8 +19,9 @@ Future<void> main() async {
|
|||
section('Find Java');
|
||||
|
||||
final String? javaHome = await findJavaHome();
|
||||
if (javaHome == null)
|
||||
if (javaHome == null) {
|
||||
return TaskResult.failure('Could not find Java');
|
||||
}
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
section('Create project');
|
||||
|
|
|
@ -19,8 +19,9 @@ Future<void> main() async {
|
|||
section('Find Java');
|
||||
|
||||
final String? javaHome = await findJavaHome();
|
||||
if (javaHome == null)
|
||||
if (javaHome == null) {
|
||||
return TaskResult.failure('Could not find Java');
|
||||
}
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
|
||||
|
|
|
@ -42,8 +42,9 @@ class BackButtonMemoryTest extends MemoryTest {
|
|||
prepareForNextMessage('READY');
|
||||
final String output = await device!.shellEval('am', <String>['start', '-n', '$packageName/$activityName']);
|
||||
print('adb shell am start: $output');
|
||||
if (output.contains('Error'))
|
||||
if (output.contains('Error')) {
|
||||
fail('unable to launch activity');
|
||||
}
|
||||
await receivedNextMessage;
|
||||
|
||||
// Wait for the Flutter app to settle (e.g. run GCs).
|
||||
|
|
|
@ -90,12 +90,15 @@ Future<int> runTest({bool coverage = false, bool noPub = false}) async {
|
|||
});
|
||||
final int result = await analysis.exitCode;
|
||||
clock.stop();
|
||||
if (result != 0)
|
||||
if (result != 0) {
|
||||
throw Exception('flutter test failed with exit code $result');
|
||||
if (badLines > 0)
|
||||
}
|
||||
if (badLines > 0) {
|
||||
throw Exception('flutter test rendered unexpected output ($badLines bad lines)');
|
||||
if (step != TestStep.testPassed)
|
||||
}
|
||||
if (step != TestStep.testPassed) {
|
||||
throw Exception('flutter test did not finish (only reached step $step)');
|
||||
}
|
||||
print('elapsed time: ${clock.elapsedMilliseconds}ms');
|
||||
return clock.elapsedMilliseconds;
|
||||
}
|
||||
|
|
|
@ -258,19 +258,22 @@ Future<void> main() async {
|
|||
]);
|
||||
});
|
||||
|
||||
if (result.exitCode == 0)
|
||||
if (result.exitCode == 0) {
|
||||
throw failure(
|
||||
'Gradle did not exit with error as expected', result);
|
||||
}
|
||||
String output = '${result.stdout}\n${result.stderr}';
|
||||
if (output.contains('GradleException') ||
|
||||
output.contains('Failed to notify') ||
|
||||
output.contains('at org.gradle'))
|
||||
output.contains('at org.gradle')) {
|
||||
throw failure(
|
||||
'Gradle output should not contain stacktrace', result);
|
||||
if (!output.contains('Build failed'))
|
||||
}
|
||||
if (!output.contains('Build failed')) {
|
||||
throw failure(
|
||||
'Gradle output should contain a readable error message',
|
||||
result);
|
||||
}
|
||||
|
||||
section('flutter build apk on build script with error');
|
||||
await project.introduceError();
|
||||
|
@ -280,18 +283,21 @@ Future<void> main() async {
|
|||
'--release',
|
||||
]);
|
||||
});
|
||||
if (result.exitCode == 0)
|
||||
if (result.exitCode == 0) {
|
||||
throw failure(
|
||||
'flutter build apk should fail when Gradle does', result);
|
||||
}
|
||||
output = '${result.stdout}\n${result.stderr}';
|
||||
if (!output.contains('Build failed'))
|
||||
if (!output.contains('Build failed')) {
|
||||
throw failure(
|
||||
'flutter build apk output should contain a readable Gradle error message',
|
||||
result);
|
||||
if (hasMultipleOccurrences(output, 'Build failed'))
|
||||
}
|
||||
if (hasMultipleOccurrences(output, 'Build failed')) {
|
||||
throw failure(
|
||||
'flutter build apk should not invoke Gradle repeatedly on error',
|
||||
result);
|
||||
}
|
||||
});
|
||||
|
||||
await runProjectTest((FlutterProject project) async {
|
||||
|
@ -303,12 +309,14 @@ Future<void> main() async {
|
|||
'--release',
|
||||
]);
|
||||
});
|
||||
if (result.exitCode == 0)
|
||||
if (result.exitCode == 0) {
|
||||
throw failure(
|
||||
'Gradle did not exit with error as expected', result);
|
||||
}
|
||||
final String output = '${result.stdout}\n${result.stderr}';
|
||||
if (!output.contains('No file or variants found for asset: lib/gallery/example_code.dart.'))
|
||||
if (!output.contains('No file or variants found for asset: lib/gallery/example_code.dart.')) {
|
||||
throw failure(output, result);
|
||||
}
|
||||
});
|
||||
|
||||
return TaskResult.success(null);
|
||||
|
|
|
@ -23,8 +23,9 @@ Future<void> main() async {
|
|||
section('Find Java');
|
||||
|
||||
final String? javaHome = await findJavaHome();
|
||||
if (javaHome == null)
|
||||
if (javaHome == null) {
|
||||
return TaskResult.failure('Could not find Java');
|
||||
}
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
section('Create Flutter module project');
|
||||
|
|
|
@ -26,8 +26,9 @@ Future<void> main() async {
|
|||
section('Find Java');
|
||||
|
||||
final String? javaHome = await findJavaHome();
|
||||
if (javaHome == null)
|
||||
if (javaHome == null) {
|
||||
return TaskResult.failure('Could not find Java');
|
||||
}
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
section('Create Flutter module project');
|
||||
|
|
|
@ -66,8 +66,9 @@ void main() {
|
|||
});
|
||||
unawaited(run.exitCode.then<void>((int exitCode) { ok = false; }));
|
||||
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
|
||||
if (!ok)
|
||||
if (!ok) {
|
||||
throw 'Failed to run test app.';
|
||||
}
|
||||
print('drive: starting...');
|
||||
final Process drive = await startProcess(
|
||||
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
||||
|
@ -90,11 +91,13 @@ void main() {
|
|||
await flutter('install', options: <String>[
|
||||
'--uninstall-only',
|
||||
]);
|
||||
if (result != 0)
|
||||
if (result != 0) {
|
||||
throw 'Failed to drive test app (exit code $result).';
|
||||
}
|
||||
result = await run.exitCode;
|
||||
if (result != 0)
|
||||
if (result != 0) {
|
||||
throw 'Received unexpected exit code $result from run process.';
|
||||
}
|
||||
});
|
||||
return TaskResult.success(null);
|
||||
});
|
||||
|
|
|
@ -52,8 +52,9 @@ void main() {
|
|||
});
|
||||
unawaited(run.exitCode.then<void>((int exitCode) { ok = false; }));
|
||||
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
|
||||
if (!ok)
|
||||
if (!ok) {
|
||||
throw 'Failed to run test app.';
|
||||
}
|
||||
|
||||
final VmService client = await vmServiceConnectUri('ws://localhost:$vmServicePort/ws');
|
||||
final VM vm = await client.getVM();
|
||||
|
@ -114,14 +115,16 @@ void main() {
|
|||
|
||||
run.stdin.write('q');
|
||||
final int result = await run.exitCode;
|
||||
if (result != 0)
|
||||
if (result != 0) {
|
||||
throw 'Received unexpected exit code $result from run process.';
|
||||
}
|
||||
});
|
||||
return TaskResult.success(null);
|
||||
});
|
||||
}
|
||||
|
||||
void expect(bool value) {
|
||||
if (!value)
|
||||
if (!value) {
|
||||
throw 'failed assertion in service extensions test';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ Future<void> main() async {
|
|||
deviceOperatingSystem = DeviceOperatingSystem.fake;
|
||||
await task(() async {
|
||||
final Device device = await devices.workingDevice;
|
||||
if (device.deviceId == 'FAKE_SUCCESS')
|
||||
if (device.deviceId == 'FAKE_SUCCESS') {
|
||||
return TaskResult.success(<String, dynamic>{
|
||||
'metric1': 42,
|
||||
'metric2': 123,
|
||||
|
@ -20,7 +20,8 @@ Future<void> main() async {
|
|||
'metric1',
|
||||
'metric2',
|
||||
]);
|
||||
else
|
||||
} else {
|
||||
return TaskResult.failure('Failed');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,35 +36,46 @@ final RegExp dartVersionPattern = RegExp(r'// *@dart *= *(\d+).(\d+)');
|
|||
final Version firstNullSafeDartVersion = Version(2, 12, 0);
|
||||
|
||||
Future<double> findCostsForFile(File file) async {
|
||||
if (path.extension(file.path) == '.py')
|
||||
if (path.extension(file.path) == '.py') {
|
||||
return pythonCost;
|
||||
}
|
||||
if (path.extension(file.path) != '.dart' &&
|
||||
path.extension(file.path) != '.yaml' &&
|
||||
path.extension(file.path) != '.sh')
|
||||
path.extension(file.path) != '.sh') {
|
||||
return 0.0;
|
||||
}
|
||||
final bool isTest = file.path.endsWith('_test.dart');
|
||||
final bool isDart = file.path.endsWith('.dart');
|
||||
double total = 0.0;
|
||||
for (final String line in await file.readAsLines()) {
|
||||
if (line.contains(todoPattern))
|
||||
if (line.contains(todoPattern)) {
|
||||
total += todoCost;
|
||||
if (line.contains(ignorePattern))
|
||||
}
|
||||
if (line.contains(ignorePattern)) {
|
||||
total += ignoreCost;
|
||||
if (line.contains(ignoreForFilePattern))
|
||||
}
|
||||
if (line.contains(ignoreForFilePattern)) {
|
||||
total += ignoreForFileCost;
|
||||
if (!isTest && line.contains(asDynamicPattern))
|
||||
}
|
||||
if (!isTest && line.contains(asDynamicPattern)) {
|
||||
total += asDynamicCost;
|
||||
if (line.contains(deprecationPattern))
|
||||
}
|
||||
if (line.contains(deprecationPattern)) {
|
||||
total += deprecationCost;
|
||||
if (line.contains(legacyDeprecationPattern))
|
||||
}
|
||||
if (line.contains(legacyDeprecationPattern)) {
|
||||
total += legacyDeprecationCost;
|
||||
if (isTest && line.contains('skip:') && !line.contains('[intended]'))
|
||||
}
|
||||
if (isTest && line.contains('skip:') && !line.contains('[intended]')) {
|
||||
total += skipCost;
|
||||
if (isDart && isOptingOutOfNullSafety(line))
|
||||
}
|
||||
if (isDart && isOptingOutOfNullSafety(line)) {
|
||||
total += fileNullSafetyMigrationCost;
|
||||
}
|
||||
}
|
||||
if (path.basename(file.path) == 'pubspec.yaml' && !packageIsNullSafe(file))
|
||||
if (path.basename(file.path) == 'pubspec.yaml' && !packageIsNullSafe(file)) {
|
||||
total += packageNullSafetyMigrationCost;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -89,12 +100,14 @@ bool packageIsNullSafe(File file) {
|
|||
}
|
||||
|
||||
Future<int> findGlobalsForFile(File file) async {
|
||||
if (path.extension(file.path) != '.dart')
|
||||
if (path.extension(file.path) != '.dart') {
|
||||
return 0;
|
||||
}
|
||||
int total = 0;
|
||||
for (final String line in await file.readAsLines()) {
|
||||
if (line.contains(globalsPattern))
|
||||
if (line.contains(globalsPattern)) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
@ -106,11 +119,13 @@ Future<double> findCostsForRepo() async {
|
|||
workingDirectory: flutterDirectory.path,
|
||||
);
|
||||
double total = 0.0;
|
||||
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()))
|
||||
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter())) {
|
||||
total += await findCostsForFile(File(path.join(flutterDirectory.path, entry)));
|
||||
}
|
||||
final int gitExitCode = await git.exitCode;
|
||||
if (gitExitCode != 0)
|
||||
if (gitExitCode != 0) {
|
||||
throw Exception('git exit with unexpected error code $gitExitCode');
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -121,11 +136,13 @@ Future<int> findGlobalsForTool() async {
|
|||
workingDirectory: flutterDirectory.path,
|
||||
);
|
||||
int total = 0;
|
||||
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()))
|
||||
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter())) {
|
||||
total += await findGlobalsForFile(File(path.join(flutterDirectory.path, entry)));
|
||||
}
|
||||
final int gitExitCode = await git.exitCode;
|
||||
if (gitExitCode != 0)
|
||||
if (gitExitCode != 0) {
|
||||
throw Exception('git exit with unexpected error code $gitExitCode');
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
@ -135,8 +152,9 @@ Future<int> countDependencies() async {
|
|||
options: <String>['--transitive-closure'],
|
||||
)).split('\n');
|
||||
final int count = lines.where((String line) => line.contains('->')).length;
|
||||
if (count < 2) // we'll always have flutter and flutter_test, at least...
|
||||
if (count < 2) {
|
||||
throw Exception('"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}');
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -146,8 +164,9 @@ Future<int> countConsumerDependencies() async {
|
|||
options: <String>['--transitive-closure', '--consumer-only'],
|
||||
)).split('\n');
|
||||
final int count = lines.where((String line) => line.contains('->')).length;
|
||||
if (count < 2) // we'll always have flutter and flutter_test, at least...
|
||||
if (count < 2) {
|
||||
throw Exception('"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}');
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -410,8 +410,9 @@ Future<void> _runGradleTask({
|
|||
print('stderr:');
|
||||
print(result.stderr);
|
||||
}
|
||||
if (result.exitCode != 0)
|
||||
if (result.exitCode != 0) {
|
||||
throw 'Gradle exited with error';
|
||||
}
|
||||
}
|
||||
|
||||
Future<ProcessResult> _resultOfGradleTask({
|
||||
|
@ -422,8 +423,9 @@ Future<ProcessResult> _resultOfGradleTask({
|
|||
section('Find Java');
|
||||
final String? javaHome = await findJavaHome();
|
||||
|
||||
if (javaHome == null)
|
||||
if (javaHome == null) {
|
||||
throw TaskResult.failure('Could not find Java');
|
||||
}
|
||||
|
||||
print('\nUsing JAVA_HOME=$javaHome');
|
||||
|
||||
|
|
|
@ -252,8 +252,9 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
|
|||
.map<AndroidDevice>((String id) => AndroidDevice(deviceId: id))
|
||||
.toList();
|
||||
|
||||
if (allDevices.isEmpty)
|
||||
if (allDevices.isEmpty) {
|
||||
throw const DeviceException('No Android devices detected');
|
||||
}
|
||||
|
||||
if (cpu != null) {
|
||||
for (final AndroidDevice device in allDevices) {
|
||||
|
@ -268,8 +269,9 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
|
|||
_workingDevice = allDevices[math.Random().nextInt(allDevices.length)];
|
||||
}
|
||||
|
||||
if (_workingDevice == null)
|
||||
if (_workingDevice == null) {
|
||||
throw const DeviceException('Cannot find a suitable Android device');
|
||||
}
|
||||
|
||||
print('Device chosen: $_workingDevice');
|
||||
}
|
||||
|
@ -300,11 +302,13 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
|
|||
final List<String> results = <String>[];
|
||||
for (final String line in output) {
|
||||
// Skip lines like: * daemon started successfully *
|
||||
if (line.startsWith('* daemon '))
|
||||
if (line.startsWith('* daemon ')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith('List of devices'))
|
||||
if (line.startsWith('List of devices')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_kDeviceRegex.hasMatch(line)) {
|
||||
final Match match = _kDeviceRegex.firstMatch(line)!;
|
||||
|
@ -551,15 +555,17 @@ class AndroidDevice extends Device {
|
|||
/// Wake up the device if it is not awake using [togglePower].
|
||||
@override
|
||||
Future<void> wakeUp() async {
|
||||
if (!(await isAwake()))
|
||||
if (!(await isAwake())) {
|
||||
await togglePower();
|
||||
}
|
||||
}
|
||||
|
||||
/// Send the device to sleep mode if it is not asleep using [togglePower].
|
||||
@override
|
||||
Future<void> sendToSleep() async {
|
||||
if (!(await isAsleep()))
|
||||
if (!(await isAsleep())) {
|
||||
await togglePower();
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends `KEYCODE_HOME` (3), which causes the device to go to the home screen.
|
||||
|
@ -840,8 +846,9 @@ class IosDeviceDiscovery implements DeviceDiscovery {
|
|||
.map<IosDevice>((String id) => IosDevice(deviceId: id))
|
||||
.toList();
|
||||
|
||||
if (allDevices.isEmpty)
|
||||
if (allDevices.isEmpty) {
|
||||
throw const DeviceException('No iOS devices detected');
|
||||
}
|
||||
|
||||
// TODO(yjbanov): filter out and warn about those with low battery level
|
||||
_workingDevice = allDevices[math.Random().nextInt(allDevices.length)];
|
||||
|
@ -1211,8 +1218,9 @@ String get adbPath {
|
|||
|
||||
final String adbPath = path.join(androidHome, 'platform-tools/adb');
|
||||
|
||||
if (!canRun(adbPath))
|
||||
if (!canRun(adbPath)) {
|
||||
throw DeviceException('adb not found at: $adbPath');
|
||||
}
|
||||
|
||||
return path.absolute(adbPath);
|
||||
}
|
||||
|
|
|
@ -46,8 +46,9 @@ bool _isTaskRegistered = false;
|
|||
/// If no `processManager` is provided, a default [LocalProcessManager] is created
|
||||
/// for the task.
|
||||
Future<TaskResult> task(TaskFunction task, { ProcessManager? processManager }) async {
|
||||
if (_isTaskRegistered)
|
||||
if (_isTaskRegistered) {
|
||||
throw StateError('A task is already registered');
|
||||
}
|
||||
_isTaskRegistered = true;
|
||||
|
||||
processManager ??= const LocalProcessManager();
|
||||
|
@ -163,8 +164,9 @@ class _TaskRunner {
|
|||
}
|
||||
|
||||
Future<TaskResult> futureResult = _performTask();
|
||||
if (taskTimeout != null)
|
||||
if (taskTimeout != null) {
|
||||
futureResult = futureResult.timeout(taskTimeout);
|
||||
}
|
||||
|
||||
result = await futureResult;
|
||||
} finally {
|
||||
|
@ -241,8 +243,9 @@ class _TaskRunner {
|
|||
/// Causes the Dart VM to stay alive until a request to run the task is
|
||||
/// received via the VM service protocol.
|
||||
void keepVmAliveUntilTaskRunRequested() {
|
||||
if (_taskStarted)
|
||||
if (_taskStarted) {
|
||||
throw StateError('Task already started.');
|
||||
}
|
||||
|
||||
// Merely creating this port object will cause the VM to stay alive and keep
|
||||
// the VM service server running until the port is disposed of.
|
||||
|
@ -280,8 +283,9 @@ class _TaskRunner {
|
|||
// are catching errors coming from arbitrary (and untrustworthy) task
|
||||
// code. Our goal is to convert the failure into a readable message.
|
||||
// Propagating it further is not useful.
|
||||
if (!completer.isCompleted)
|
||||
if (!completer.isCompleted) {
|
||||
completer.complete(TaskResult.failure(message));
|
||||
}
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
|
|
@ -156,8 +156,9 @@ Future<TaskResult> runTask(
|
|||
}) async {
|
||||
final String taskExecutable = 'bin/tasks/$taskName.dart';
|
||||
|
||||
if (!file(taskExecutable).existsSync())
|
||||
if (!file(taskExecutable).existsSync()) {
|
||||
throw 'Executable Dart file not found: $taskExecutable';
|
||||
}
|
||||
|
||||
final Process runner = await startProcess(
|
||||
dartBin,
|
||||
|
@ -190,8 +191,9 @@ Future<TaskResult> runTask(
|
|||
.listen((String line) {
|
||||
if (!uri.isCompleted) {
|
||||
final Uri? serviceUri = parseServiceUri(line, prefix: RegExp('(Observatory|The Dart VM service is) listening on '));
|
||||
if (serviceUri != null)
|
||||
if (serviceUri != null) {
|
||||
uri.complete(serviceUri);
|
||||
}
|
||||
}
|
||||
if (!silent) {
|
||||
stdout.writeln('[$taskName] [STDOUT] $line');
|
||||
|
@ -255,12 +257,14 @@ Future<ConnectionResult> _connectToRunnerIsolate(Uri vmServiceUri) async {
|
|||
}
|
||||
final IsolateRef isolate = vm.isolates!.first;
|
||||
final Response response = await client.callServiceExtension('ext.cocoonRunnerReady', isolateId: isolate.id);
|
||||
if (response.json!['response'] != 'ready')
|
||||
if (response.json!['response'] != 'ready') {
|
||||
throw 'not ready yet';
|
||||
}
|
||||
return ConnectionResult(client, isolate);
|
||||
} catch (error) {
|
||||
if (stopwatch.elapsed > const Duration(seconds: 10))
|
||||
if (stopwatch.elapsed > const Duration(seconds: 10)) {
|
||||
print('VM service still not ready after ${stopwatch.elapsed}: $error\nContinuing to retry...');
|
||||
}
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,14 +126,15 @@ void copy(File sourceFile, Directory targetDirectory, {String? name}) {
|
|||
}
|
||||
|
||||
void recursiveCopy(Directory source, Directory target) {
|
||||
if (!target.existsSync())
|
||||
if (!target.existsSync()) {
|
||||
target.createSync();
|
||||
}
|
||||
|
||||
for (final FileSystemEntity entity in source.listSync(followLinks: false)) {
|
||||
final String name = path.basename(entity.path);
|
||||
if (entity is Directory && !entity.path.contains('.dart_tool'))
|
||||
if (entity is Directory && !entity.path.contains('.dart_tool')) {
|
||||
recursiveCopy(entity, Directory(path.join(target.path, name)));
|
||||
else if (entity is File) {
|
||||
} else if (entity is File) {
|
||||
final File dest = File(path.join(target.path, name));
|
||||
dest.writeAsBytesSync(entity.readAsBytesSync());
|
||||
// Preserve executable bit
|
||||
|
@ -194,8 +195,9 @@ void section(String title) {
|
|||
title = '╡ ••• $title ••• ╞';
|
||||
final String line = '═' * math.max((80 - title.length) ~/ 2, 2);
|
||||
output = '$line$title$line';
|
||||
if (output.length == 79)
|
||||
if (output.length == 79) {
|
||||
output += '═';
|
||||
}
|
||||
}
|
||||
print('\n\n$output\n');
|
||||
}
|
||||
|
@ -209,10 +211,12 @@ Future<String> getDartVersion() async {
|
|||
// Dart VM version: 1.17.0-dev.2.0 (Tue May 3 12:14:52 2016) on "macos_x64"
|
||||
// to:
|
||||
// 1.17.0-dev.2.0
|
||||
if (version.contains('('))
|
||||
if (version.contains('(')) {
|
||||
version = version.substring(0, version.indexOf('(')).trim();
|
||||
if (version.contains(':'))
|
||||
}
|
||||
if (version.contains(':')) {
|
||||
version = version.substring(version.indexOf(':') + 1).trim();
|
||||
}
|
||||
|
||||
return version.replaceAll('"', "'");
|
||||
}
|
||||
|
@ -295,8 +299,9 @@ Future<Process> startProcess(
|
|||
}
|
||||
|
||||
Future<void> forceQuitRunningProcesses() async {
|
||||
if (_runningProcesses.isEmpty)
|
||||
if (_runningProcesses.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give normally quitting processes a chance to report their exit code.
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
@ -354,8 +359,9 @@ Future<int> _execute(
|
|||
);
|
||||
final int exitCode = await process.exitCode;
|
||||
|
||||
if (exitCode != 0 && !canFail)
|
||||
if (exitCode != 0 && !canFail) {
|
||||
fail('Executable "$executable" failed with exit code $exitCode.');
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
@ -545,8 +551,9 @@ Future<String?> findJavaHome() async {
|
|||
'Java binary at: ',
|
||||
from: await evalFlutter('doctor', options: <String>['-v']),
|
||||
);
|
||||
if (hits.isEmpty)
|
||||
if (hits.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final String javaBinary = hits.first
|
||||
.split(': ')
|
||||
.last;
|
||||
|
@ -579,8 +586,9 @@ void cd(dynamic directory) {
|
|||
throw FileSystemException('Unsupported directory type ${directory.runtimeType}', directory.toString());
|
||||
}
|
||||
|
||||
if (!d.existsSync())
|
||||
if (!d.existsSync()) {
|
||||
throw FileSystemException('Cannot cd into directory that does not exist', d.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Directory get flutterDirectory => Directory.current.parent.parent;
|
||||
|
@ -590,15 +598,17 @@ Directory get openpayDirectory => Directory(requireEnvVar('OPENPAY_CHECKOUT_PATH
|
|||
String requireEnvVar(String name) {
|
||||
final String? value = Platform.environment[name];
|
||||
|
||||
if (value == null)
|
||||
if (value == null) {
|
||||
fail('$name environment variable is missing. Quitting.');
|
||||
}
|
||||
|
||||
return value!;
|
||||
}
|
||||
|
||||
T requireConfigProperty<T>(Map<String, dynamic> map, String propertyName) {
|
||||
if (!map.containsKey(propertyName))
|
||||
if (!map.containsKey(propertyName)) {
|
||||
fail('Configuration property not found: $propertyName');
|
||||
}
|
||||
final T result = map[propertyName] as T;
|
||||
return result;
|
||||
}
|
||||
|
@ -634,26 +644,36 @@ void checkNotNull(Object o1,
|
|||
Object o8 = 1,
|
||||
Object o9 = 1,
|
||||
Object o10 = 1]) {
|
||||
if (o1 == null)
|
||||
if (o1 == null) {
|
||||
throw 'o1 is null';
|
||||
if (o2 == null)
|
||||
}
|
||||
if (o2 == null) {
|
||||
throw 'o2 is null';
|
||||
if (o3 == null)
|
||||
}
|
||||
if (o3 == null) {
|
||||
throw 'o3 is null';
|
||||
if (o4 == null)
|
||||
}
|
||||
if (o4 == null) {
|
||||
throw 'o4 is null';
|
||||
if (o5 == null)
|
||||
}
|
||||
if (o5 == null) {
|
||||
throw 'o5 is null';
|
||||
if (o6 == null)
|
||||
}
|
||||
if (o6 == null) {
|
||||
throw 'o6 is null';
|
||||
if (o7 == null)
|
||||
}
|
||||
if (o7 == null) {
|
||||
throw 'o7 is null';
|
||||
if (o8 == null)
|
||||
}
|
||||
if (o8 == null) {
|
||||
throw 'o8 is null';
|
||||
if (o9 == null)
|
||||
}
|
||||
if (o9 == null) {
|
||||
throw 'o9 is null';
|
||||
if (o10 == null)
|
||||
}
|
||||
if (o10 == null) {
|
||||
throw 'o10 is null';
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits [from] into lines and selects those that contain [pattern].
|
||||
|
|
|
@ -74,8 +74,9 @@ Future<Map<String, double>> readJsonResults(Process process) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (jsonStarted && line.contains(jsonPrefix))
|
||||
if (jsonStarted && line.contains(jsonPrefix)) {
|
||||
jsonBuf.writeln(line.substring(line.indexOf(jsonPrefix) + jsonPrefix.length));
|
||||
}
|
||||
});
|
||||
|
||||
process.exitCode.then<void>((int code) async {
|
||||
|
|
|
@ -288,8 +288,9 @@ TaskFunction createBasicMaterialCompileTest() {
|
|||
await flutter('create', options: <String>['--template=app', sampleAppName]);
|
||||
});
|
||||
|
||||
if (!sampleDir.existsSync())
|
||||
if (!sampleDir.existsSync()) {
|
||||
throw 'Failed to create default Flutter app in ${sampleDir.path}';
|
||||
}
|
||||
|
||||
return CompileTest(sampleDir.path).run();
|
||||
};
|
||||
|
@ -754,8 +755,9 @@ class StartupTest {
|
|||
|
||||
final Map<String, dynamic> averageResults = _average(results, iterations);
|
||||
|
||||
if (!reportMetrics)
|
||||
if (!reportMetrics) {
|
||||
return TaskResult.success(averageResults);
|
||||
}
|
||||
|
||||
return TaskResult.success(averageResults, benchmarkScoreKeys: <String>[
|
||||
'timeToFirstFrameMicros',
|
||||
|
@ -860,8 +862,9 @@ class DevtoolsStartupTest {
|
|||
device.deviceId,
|
||||
]);
|
||||
|
||||
if (sawLine)
|
||||
if (sawLine) {
|
||||
return TaskResult.success(null, benchmarkScoreKeys: <String>[]);
|
||||
}
|
||||
return TaskResult.failure('Did not see line "The Flutter DevTools debugger and profiler" in output');
|
||||
});
|
||||
}
|
||||
|
@ -1401,8 +1404,9 @@ class CompileTest {
|
|||
// IPAs are created manually, https://flutter.dev/ios-release/
|
||||
await exec('tar', <String>['-zcf', 'build/app.ipa', appPath]);
|
||||
releaseSizeInBytes = await file('$cwd/build/app.ipa').length();
|
||||
if (reportPackageContentSizes)
|
||||
if (reportPackageContentSizes) {
|
||||
metrics.addAll(await getSizesFromIosApp(appPath));
|
||||
}
|
||||
break;
|
||||
case DeviceOperatingSystem.android:
|
||||
case DeviceOperatingSystem.androidArm:
|
||||
|
@ -1416,8 +1420,9 @@ class CompileTest {
|
|||
final String apkPath = '$cwd/build/app/outputs/flutter-apk/app-release.apk';
|
||||
final File apk = file(apkPath);
|
||||
releaseSizeInBytes = apk.lengthSync();
|
||||
if (reportPackageContentSizes)
|
||||
if (reportPackageContentSizes) {
|
||||
metrics.addAll(await getSizesFromApk(apkPath));
|
||||
}
|
||||
break;
|
||||
case DeviceOperatingSystem.androidArm64:
|
||||
options.insert(0, 'apk');
|
||||
|
@ -1430,8 +1435,9 @@ class CompileTest {
|
|||
final String apkPath = '$cwd/build/app/outputs/flutter-apk/app-release.apk';
|
||||
final File apk = file(apkPath);
|
||||
releaseSizeInBytes = apk.lengthSync();
|
||||
if (reportPackageContentSizes)
|
||||
if (reportPackageContentSizes) {
|
||||
metrics.addAll(await getSizesFromApk(apkPath));
|
||||
}
|
||||
break;
|
||||
case DeviceOperatingSystem.fake:
|
||||
throw Exception('Unsupported option for fake devices');
|
||||
|
@ -1572,8 +1578,9 @@ class MemoryTest {
|
|||
|
||||
final StreamSubscription<String> adb = device!.logcat.listen(
|
||||
(String data) {
|
||||
if (data.contains('==== MEMORY BENCHMARK ==== $_nextMessage ===='))
|
||||
if (data.contains('==== MEMORY BENCHMARK ==== $_nextMessage ====')) {
|
||||
_receivedNextMessage?.complete();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -1764,8 +1771,9 @@ class ReportedDurationTest {
|
|||
|
||||
final StreamSubscription<String> adb = device!.logcat.listen(
|
||||
(String data) {
|
||||
if (durationPattern.hasMatch(data))
|
||||
if (durationPattern.hasMatch(data)) {
|
||||
durationCompleter.complete(int.parse(durationPattern.firstMatch(data)!.group(1)!));
|
||||
}
|
||||
},
|
||||
);
|
||||
print('launching $project$test on device...');
|
||||
|
|
|
@ -158,8 +158,9 @@ class CommandArgs {
|
|||
|
||||
@override
|
||||
bool operator==(Object other) {
|
||||
if (other.runtimeType != CommandArgs)
|
||||
if (other.runtimeType != CommandArgs) {
|
||||
return false;
|
||||
}
|
||||
return other is CommandArgs
|
||||
&& other.command == command
|
||||
&& const ListEquality<String>().equals(other.arguments, arguments)
|
||||
|
|
|
@ -33,10 +33,11 @@ Future<String> dataHandler(String message) async {
|
|||
});
|
||||
completer.complete(json.encode(result));
|
||||
}
|
||||
if (SchedulerBinding.instance.hasScheduledFrame)
|
||||
if (SchedulerBinding.instance.hasScheduledFrame) {
|
||||
SchedulerBinding.instance.addPostFrameCallback(completeSemantics);
|
||||
else
|
||||
} else {
|
||||
completeSemantics();
|
||||
}
|
||||
return completer.future;
|
||||
}
|
||||
if (message.contains('setClipboard')) {
|
||||
|
@ -48,10 +49,11 @@ Future<String> dataHandler(String message) async {
|
|||
});
|
||||
completer.complete('');
|
||||
}
|
||||
if (SchedulerBinding.instance.hasScheduledFrame)
|
||||
if (SchedulerBinding.instance.hasScheduledFrame) {
|
||||
SchedulerBinding.instance.addPostFrameCallback(completeSetClipboard);
|
||||
else
|
||||
} else {
|
||||
completeSetClipboard();
|
||||
}
|
||||
return completer.future;
|
||||
}
|
||||
throw UnimplementedError();
|
||||
|
|
|
@ -187,8 +187,9 @@ class Rect {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is Rect
|
||||
&& other.top == top
|
||||
&& other.left == left
|
||||
|
@ -219,8 +220,9 @@ class Size {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is Size
|
||||
&& other.width == width
|
||||
&& other.height == height;
|
||||
|
|
|
@ -201,8 +201,9 @@ class AndroidSemanticsAction {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is AndroidSemanticsAction
|
||||
&& other.id == id;
|
||||
}
|
||||
|
|
|
@ -100,53 +100,74 @@ class _AndroidSemanticsMatcher extends Matcher {
|
|||
@override
|
||||
Description describe(Description description) {
|
||||
description.add('AndroidSemanticsNode');
|
||||
if (text != null)
|
||||
if (text != null) {
|
||||
description.add(' with text: $text');
|
||||
if (contentDescription != null)
|
||||
}
|
||||
if (contentDescription != null) {
|
||||
description.add( 'with contentDescription $contentDescription');
|
||||
if (className != null)
|
||||
}
|
||||
if (className != null) {
|
||||
description.add(' with className: $className');
|
||||
if (id != null)
|
||||
}
|
||||
if (id != null) {
|
||||
description.add(' with id: $id');
|
||||
if (actions != null)
|
||||
}
|
||||
if (actions != null) {
|
||||
description.add(' with actions: $actions');
|
||||
if (rect != null)
|
||||
}
|
||||
if (rect != null) {
|
||||
description.add(' with rect: $rect');
|
||||
if (size != null)
|
||||
}
|
||||
if (size != null) {
|
||||
description.add(' with size: $size');
|
||||
if (isChecked != null)
|
||||
}
|
||||
if (isChecked != null) {
|
||||
description.add(' with flag isChecked: $isChecked');
|
||||
if (isEditable != null)
|
||||
}
|
||||
if (isEditable != null) {
|
||||
description.add(' with flag isEditable: $isEditable');
|
||||
if (isEnabled != null)
|
||||
}
|
||||
if (isEnabled != null) {
|
||||
description.add(' with flag isEnabled: $isEnabled');
|
||||
if (isFocusable != null)
|
||||
}
|
||||
if (isFocusable != null) {
|
||||
description.add(' with flag isFocusable: $isFocusable');
|
||||
if (isFocused != null)
|
||||
}
|
||||
if (isFocused != null) {
|
||||
description.add(' with flag isFocused: $isFocused');
|
||||
if (isHeading != null)
|
||||
}
|
||||
if (isHeading != null) {
|
||||
description.add(' with flag isHeading: $isHeading');
|
||||
if (isPassword != null)
|
||||
}
|
||||
if (isPassword != null) {
|
||||
description.add(' with flag isPassword: $isPassword');
|
||||
if (isLongClickable != null)
|
||||
}
|
||||
if (isLongClickable != null) {
|
||||
description.add(' with flag isLongClickable: $isLongClickable');
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
@override
|
||||
bool matches(covariant AndroidSemanticsNode item, Map<Object, Object> matchState) {
|
||||
if (text != null && text != item.text)
|
||||
if (text != null && text != item.text) {
|
||||
return _failWithMessage('Expected text: $text', matchState);
|
||||
if (contentDescription != null && contentDescription != item.contentDescription)
|
||||
}
|
||||
if (contentDescription != null && contentDescription != item.contentDescription) {
|
||||
return _failWithMessage('Expected contentDescription: $contentDescription', matchState);
|
||||
if (className != null && className != item.className)
|
||||
}
|
||||
if (className != null && className != item.className) {
|
||||
return _failWithMessage('Expected className: $className', matchState);
|
||||
if (id != null && id != item.id)
|
||||
}
|
||||
if (id != null && id != item.id) {
|
||||
return _failWithMessage('Expected id: $id', matchState);
|
||||
if (rect != null && rect != item.getRect())
|
||||
}
|
||||
if (rect != null && rect != item.getRect()) {
|
||||
return _failWithMessage('Expected rect: $rect', matchState);
|
||||
if (size != null && size != item.getSize())
|
||||
}
|
||||
if (size != null && size != item.getSize()) {
|
||||
return _failWithMessage('Expected size: $size', matchState);
|
||||
}
|
||||
if (actions != null) {
|
||||
final List<AndroidSemanticsAction> itemActions = item.getActions();
|
||||
if (!unorderedEquals(actions).matches(itemActions, matchState)) {
|
||||
|
@ -161,25 +182,34 @@ class _AndroidSemanticsMatcher extends Matcher {
|
|||
return _failWithMessage('Expected actions: $actionsString\nActual actions: $itemActionsString\nUnexpected: $unexpectedInString\nMissing: $missingInString', matchState);
|
||||
}
|
||||
}
|
||||
if (isChecked != null && isChecked != item.isChecked)
|
||||
if (isChecked != null && isChecked != item.isChecked) {
|
||||
return _failWithMessage('Expected isChecked: $isChecked', matchState);
|
||||
if (isCheckable != null && isCheckable != item.isCheckable)
|
||||
}
|
||||
if (isCheckable != null && isCheckable != item.isCheckable) {
|
||||
return _failWithMessage('Expected isCheckable: $isCheckable', matchState);
|
||||
if (isEditable != null && isEditable != item.isEditable)
|
||||
}
|
||||
if (isEditable != null && isEditable != item.isEditable) {
|
||||
return _failWithMessage('Expected isEditable: $isEditable', matchState);
|
||||
if (isEnabled != null && isEnabled != item.isEnabled)
|
||||
}
|
||||
if (isEnabled != null && isEnabled != item.isEnabled) {
|
||||
return _failWithMessage('Expected isEnabled: $isEnabled', matchState);
|
||||
if (isFocusable != null && isFocusable != item.isFocusable)
|
||||
}
|
||||
if (isFocusable != null && isFocusable != item.isFocusable) {
|
||||
return _failWithMessage('Expected isFocusable: $isFocusable', matchState);
|
||||
if (isFocused != null && isFocused != item.isFocused)
|
||||
}
|
||||
if (isFocused != null && isFocused != item.isFocused) {
|
||||
return _failWithMessage('Expected isFocused: $isFocused', matchState);
|
||||
}
|
||||
// Heading is not available in all Android versions, so match anything if it is not set by the platform
|
||||
if (isHeading != null && isHeading != item.isHeading && item.isHeading != null)
|
||||
if (isHeading != null && isHeading != item.isHeading && item.isHeading != null) {
|
||||
return _failWithMessage('Expected isHeading: $isHeading', matchState);
|
||||
if (isPassword != null && isPassword != item.isPassword)
|
||||
}
|
||||
if (isPassword != null && isPassword != item.isPassword) {
|
||||
return _failWithMessage('Expected isPassword: $isPassword', matchState);
|
||||
if (isLongClickable != null && isLongClickable != item.isLongClickable)
|
||||
}
|
||||
if (isLongClickable != null && isLongClickable != item.isLongClickable) {
|
||||
return _failWithMessage('Expected longClickable: $isLongClickable', matchState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,17 +47,19 @@ void diffActions(StringBuffer diffBuffer, Map<String, dynamic> originalEvent,
|
|||
final String originalActionName =
|
||||
getActionName(originalActionMasked, originalEvent['action'] as int);
|
||||
|
||||
if (synthesizedActionMasked != originalActionMasked)
|
||||
if (synthesizedActionMasked != originalActionMasked) {
|
||||
diffBuffer.write(
|
||||
'action (expected: $originalActionName actual: $synthesizedActionName) ');
|
||||
}
|
||||
|
||||
if (kPointerActions.contains(originalActionMasked) &&
|
||||
originalActionMasked == synthesizedActionMasked) {
|
||||
final int originalPointer = getPointerIdx(originalEvent['action'] as int);
|
||||
final int synthesizedPointer = getPointerIdx(synthesizedEvent['action'] as int);
|
||||
if (originalPointer != synthesizedPointer)
|
||||
if (originalPointer != synthesizedPointer) {
|
||||
diffBuffer.write(
|
||||
'pointerIdx (expected: $originalPointer actual: $synthesizedPointer action: $originalActionName ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,10 +125,12 @@ void diffMaps(
|
|||
return;
|
||||
}
|
||||
for (final String key in expected.keys) {
|
||||
if (excludeKeys.contains(key))
|
||||
if (excludeKeys.contains(key)) {
|
||||
continue;
|
||||
if (doublesApproximatelyMatch(expected[key], actual[key]))
|
||||
}
|
||||
if (doublesApproximatelyMatch(expected[key], actual[key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expected[key] != actual[key]) {
|
||||
diffBuffer.write(
|
||||
|
@ -155,10 +159,11 @@ String getActionName(int actionMasked, int action) {
|
|||
'BUTTON_PRESS',
|
||||
'BUTTON_RELEASE',
|
||||
];
|
||||
if (actionMasked < actionNames.length)
|
||||
if (actionMasked < actionNames.length) {
|
||||
return '${actionNames[actionMasked]}($action)';
|
||||
else
|
||||
} else {
|
||||
return 'ACTION_$actionMasked';
|
||||
}
|
||||
}
|
||||
|
||||
bool doublesApproximatelyMatch(dynamic a, dynamic b) =>
|
||||
|
|
|
@ -146,16 +146,19 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
await channel.invokeMethod<void>('stopFlutterViewEvents');
|
||||
await viewChannel?.invokeMethod<void>('stopTouchEvents');
|
||||
|
||||
if (flutterViewEvents.length != embeddedViewEvents.length)
|
||||
if (flutterViewEvents.length != embeddedViewEvents.length) {
|
||||
return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
|
||||
}
|
||||
|
||||
final StringBuffer diff = StringBuffer();
|
||||
for (int i = 0; i < flutterViewEvents.length; ++i) {
|
||||
final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
|
||||
if (currentDiff.isEmpty)
|
||||
if (currentDiff.isEmpty) {
|
||||
continue;
|
||||
if (diff.isNotEmpty)
|
||||
}
|
||||
if (diff.isNotEmpty) {
|
||||
diff.write(', ');
|
||||
}
|
||||
diff.write(currentDiff);
|
||||
}
|
||||
return diff.toString();
|
||||
|
@ -229,8 +232,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
case 'onTouch':
|
||||
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
|
||||
flutterViewEvents.insert(0, map.cast<String, dynamic>());
|
||||
if (flutterViewEvents.length > kEventsBufferSize)
|
||||
if (flutterViewEvents.length > kEventsBufferSize) {
|
||||
flutterViewEvents.removeLast();
|
||||
}
|
||||
setState(() {});
|
||||
break;
|
||||
}
|
||||
|
@ -242,8 +246,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
case 'onTouch':
|
||||
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
|
||||
embeddedViewEvents.insert(0, map.cast<String, dynamic>());
|
||||
if (embeddedViewEvents.length > kEventsBufferSize)
|
||||
if (embeddedViewEvents.length > kEventsBufferSize) {
|
||||
embeddedViewEvents.removeLast();
|
||||
}
|
||||
setState(() {});
|
||||
break;
|
||||
}
|
||||
|
@ -251,9 +256,10 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
}
|
||||
|
||||
Widget buildEventTile(BuildContext context, int index) {
|
||||
if (embeddedViewEvents.length > index)
|
||||
if (embeddedViewEvents.length > index) {
|
||||
return TouchEventDiff(
|
||||
flutterViewEvents[index], embeddedViewEvents[index]);
|
||||
}
|
||||
return Text(
|
||||
'Unmatched event, action: ${flutterViewEvents[index]['action']}');
|
||||
}
|
||||
|
|
|
@ -172,10 +172,11 @@ class _TestAppState extends State<TestApp> {
|
|||
|
||||
void _executeNextStep() {
|
||||
setState(() {
|
||||
if (_step < steps.length)
|
||||
if (_step < steps.length) {
|
||||
_result = steps[_step++]();
|
||||
else
|
||||
} else {
|
||||
_result = Future<TestStepResult>.value(TestStepResult.complete);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -169,10 +169,11 @@ Future<TestStepResult> _basicMessageToUnknownChannel<T>(
|
|||
}
|
||||
|
||||
String toString(dynamic message) {
|
||||
if (message is ByteData)
|
||||
if (message is ByteData) {
|
||||
return message.buffer
|
||||
.asUint8List(message.offsetInBytes, message.lengthInBytes)
|
||||
.toString();
|
||||
else
|
||||
} else {
|
||||
return '$message';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,8 +101,9 @@ Future<TestStepResult> resultOfHandshake(
|
|||
dynamic error,
|
||||
) async {
|
||||
assert(message != nothing);
|
||||
while (received.length < 2)
|
||||
while (received.length < 2) {
|
||||
received.add(nothing);
|
||||
}
|
||||
TestStatus status;
|
||||
if (!_deepEquals(messageEcho, message) ||
|
||||
received.length != 2 ||
|
||||
|
@ -127,27 +128,34 @@ Future<TestStepResult> resultOfHandshake(
|
|||
}
|
||||
|
||||
String _toString(dynamic message) {
|
||||
if (message is ByteData)
|
||||
if (message is ByteData) {
|
||||
return message.buffer
|
||||
.asUint8List(message.offsetInBytes, message.lengthInBytes)
|
||||
.toString();
|
||||
else
|
||||
} else {
|
||||
return '$message';
|
||||
}
|
||||
}
|
||||
|
||||
bool _deepEquals(dynamic a, dynamic b) {
|
||||
if (a == b)
|
||||
if (a == b) {
|
||||
return true;
|
||||
if (a is double && a.isNaN)
|
||||
}
|
||||
if (a is double && a.isNaN) {
|
||||
return b is double && b.isNaN;
|
||||
if (a is ByteData)
|
||||
}
|
||||
if (a is ByteData) {
|
||||
return b is ByteData && _deepEqualsByteData(a, b);
|
||||
if (a is List)
|
||||
}
|
||||
if (a is List) {
|
||||
return b is List && _deepEqualsList(a, b);
|
||||
if (a is Map)
|
||||
}
|
||||
if (a is Map) {
|
||||
return b is Map && _deepEqualsMap(a, b);
|
||||
if (a is Pair)
|
||||
}
|
||||
if (a is Pair) {
|
||||
return b is Pair && _deepEqualsPair(a, b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -159,21 +167,25 @@ bool _deepEqualsByteData(ByteData a, ByteData b) {
|
|||
}
|
||||
|
||||
bool _deepEqualsList(List<dynamic> a, List<dynamic> b) {
|
||||
if (a.length != b.length)
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (!_deepEquals(a[i], b[i]))
|
||||
if (!_deepEquals(a[i], b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _deepEqualsMap(Map<dynamic, dynamic> a, Map<dynamic, dynamic> b) {
|
||||
if (a.length != b.length)
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
for (final dynamic key in a.keys) {
|
||||
if (!b.containsKey(key) || !_deepEquals(a[key], b[key]))
|
||||
if (!b.containsKey(key) || !_deepEquals(a[key], b[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -115,8 +115,9 @@ Press play to produce texture frames.''';
|
|||
_state = FrameState.initial;
|
||||
});
|
||||
} else {
|
||||
if ((tickCount % (calibrationTickCount ~/ 20)) == 0)
|
||||
if ((tickCount % (calibrationTickCount ~/ 20)) == 0) {
|
||||
debugPrint('Calibrating... ${(100.0 * tickCount / calibrationTickCount).floor()}%');
|
||||
}
|
||||
}
|
||||
});
|
||||
ticker.start();
|
||||
|
|
|
@ -44,8 +44,9 @@ class _RenderStatusBarPaddingSliver extends RenderSliver {
|
|||
double _maxHeight;
|
||||
set maxHeight(double value) {
|
||||
assert(maxHeight >= 0.0);
|
||||
if (_maxHeight == value)
|
||||
if (_maxHeight == value) {
|
||||
return;
|
||||
}
|
||||
_maxHeight = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
@ -56,8 +57,9 @@ class _RenderStatusBarPaddingSliver extends RenderSliver {
|
|||
double _scrollFactor;
|
||||
set scrollFactor(double value) {
|
||||
assert(scrollFactor >= 1.0);
|
||||
if (_scrollFactor == value)
|
||||
if (_scrollFactor == value) {
|
||||
return;
|
||||
}
|
||||
_scrollFactor = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
@ -390,22 +392,27 @@ class _SnappingScrollPhysics extends ClampingScrollPhysics {
|
|||
// then snap it there. Similarly if the simulation is headed down past
|
||||
// midScrollOffset but will not reach zero, then snap it to zero.
|
||||
final double simulationEnd = simulation.x(double.infinity);
|
||||
if (simulationEnd >= midScrollOffset)
|
||||
if (simulationEnd >= midScrollOffset) {
|
||||
return simulation;
|
||||
if (dragVelocity > 0.0)
|
||||
}
|
||||
if (dragVelocity > 0.0) {
|
||||
return _toMidScrollOffsetSimulation(offset, dragVelocity);
|
||||
if (dragVelocity < 0.0)
|
||||
}
|
||||
if (dragVelocity < 0.0) {
|
||||
return _toZeroScrollOffsetSimulation(offset, dragVelocity);
|
||||
}
|
||||
} else {
|
||||
// The user ended the drag with little or no velocity. If they
|
||||
// didn't leave the offset above midScrollOffset, then
|
||||
// snap to midScrollOffset if they're more than halfway there,
|
||||
// otherwise snap to zero.
|
||||
final double snapThreshold = midScrollOffset / 2.0;
|
||||
if (offset >= snapThreshold && offset < midScrollOffset)
|
||||
if (offset >= snapThreshold && offset < midScrollOffset) {
|
||||
return _toMidScrollOffsetSimulation(offset, dragVelocity);
|
||||
if (offset > 0.0 && offset < snapThreshold)
|
||||
}
|
||||
if (offset > 0.0 && offset < snapThreshold) {
|
||||
return _toZeroScrollOffsetSimulation(offset, dragVelocity);
|
||||
}
|
||||
}
|
||||
return simulation;
|
||||
}
|
||||
|
@ -439,10 +446,11 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
|
|||
}
|
||||
|
||||
void _handleBackButton(double midScrollOffset) {
|
||||
if (_scrollController.offset >= midScrollOffset)
|
||||
if (_scrollController.offset >= midScrollOffset) {
|
||||
_scrollController.animateTo(0.0, curve: _kScrollCurve, duration: _kScrollDuration);
|
||||
else
|
||||
} else {
|
||||
Navigator.maybePop(context);
|
||||
}
|
||||
}
|
||||
|
||||
// Only enable paging for the heading when the user has scrolled to midScrollOffset.
|
||||
|
@ -478,8 +486,9 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
|
|||
bool _handlePageNotification(ScrollNotification notification, PageController leader, PageController follower) {
|
||||
if (notification.depth == 0 && notification is ScrollUpdateNotification) {
|
||||
selectedIndex.value = leader.page;
|
||||
if (follower.page != leader.page)
|
||||
if (follower.page != leader.page) {
|
||||
follower.position.jumpToWithoutSettling(leader.position.pixels); // ignore: deprecated_member_use
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,12 @@ class FloatToken extends NumberToken {
|
|||
|
||||
static double _parse(String stringRep) {
|
||||
String toParse = stringRep;
|
||||
if (toParse.startsWith('.'))
|
||||
if (toParse.startsWith('.')) {
|
||||
toParse = '0$toParse';
|
||||
if (toParse.endsWith('.'))
|
||||
}
|
||||
if (toParse.endsWith('.')) {
|
||||
toParse = '${toParse}0';
|
||||
}
|
||||
return double.parse(toParse);
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +53,9 @@ class ResultToken extends NumberToken {
|
|||
/// floating point number is guaranteed to have at least this many
|
||||
/// decimal digits of precision.
|
||||
static num round(num number) {
|
||||
if (number is int)
|
||||
if (number is int) {
|
||||
return number;
|
||||
}
|
||||
return double.parse(number.toStringAsPrecision(14));
|
||||
}
|
||||
}
|
||||
|
@ -330,10 +333,11 @@ class CalcExpression {
|
|||
// Remove the next number token.
|
||||
final NumberToken nextNumToken = list.removeAt(0)! as NumberToken;
|
||||
final num nextNumber = nextNumToken.number;
|
||||
if (isDivision)
|
||||
if (isDivision) {
|
||||
currentValue /= nextNumber;
|
||||
else
|
||||
} else {
|
||||
currentValue *= nextNumber;
|
||||
}
|
||||
}
|
||||
return currentValue;
|
||||
}
|
||||
|
|
|
@ -294,23 +294,26 @@ class _BackdropDemoState extends State<BackdropDemo> with SingleTickerProviderSt
|
|||
// the user must either tap its heading or the backdrop's menu icon.
|
||||
|
||||
void _handleDragUpdate(DragUpdateDetails details) {
|
||||
if (_controller.isAnimating || _controller.status == AnimationStatus.completed)
|
||||
if (_controller.isAnimating || _controller.status == AnimationStatus.completed) {
|
||||
return;
|
||||
}
|
||||
|
||||
_controller.value -= details.primaryDelta! / _backdropHeight;
|
||||
}
|
||||
|
||||
void _handleDragEnd(DragEndDetails details) {
|
||||
if (_controller.isAnimating || _controller.status == AnimationStatus.completed)
|
||||
if (_controller.isAnimating || _controller.status == AnimationStatus.completed) {
|
||||
return;
|
||||
}
|
||||
|
||||
final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight;
|
||||
if (flingVelocity < 0.0)
|
||||
if (flingVelocity < 0.0) {
|
||||
_controller.fling(velocity: math.max(2.0, -flingVelocity));
|
||||
else if (flingVelocity > 0.0)
|
||||
} else if (flingVelocity > 0.0) {
|
||||
_controller.fling(velocity: math.min(-2.0, -flingVelocity));
|
||||
else
|
||||
} else {
|
||||
_controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Stacks a BackdropPanel, which displays the selected category, on top
|
||||
|
|
|
@ -204,12 +204,15 @@ class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
|
|||
}
|
||||
|
||||
NotchedShape? _selectNotch() {
|
||||
if (!_showNotch.value!)
|
||||
if (!_showNotch.value!) {
|
||||
return null;
|
||||
if (_fabShape == kCircularFab)
|
||||
}
|
||||
if (_fabShape == kCircularFab) {
|
||||
return const CircularNotchedRectangle();
|
||||
if (_fabShape == kDiamondFab)
|
||||
}
|
||||
if (_fabShape == kDiamondFab) {
|
||||
return const _DiamondNotchedRectangle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -452,8 +455,9 @@ class _DiamondNotchedRectangle implements NotchedShape {
|
|||
|
||||
@override
|
||||
Path getOuterPath(Rect host, Rect? guest) {
|
||||
if (!host.overlaps(guest!))
|
||||
if (!host.overlaps(guest!)) {
|
||||
return Path()..addRect(host);
|
||||
}
|
||||
assert(guest.width > 0.0);
|
||||
|
||||
final Rect intersection = guest.intersect(host);
|
||||
|
|
|
@ -165,8 +165,9 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo>
|
|||
|
||||
@override
|
||||
void dispose() {
|
||||
for (final NavigationIconView view in _navigationViews)
|
||||
for (final NavigationIconView view in _navigationViews) {
|
||||
view.controller.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -97,8 +97,9 @@ class DessertDataSource extends DataTableSource {
|
|||
@override
|
||||
DataRow? getRow(int index) {
|
||||
assert(index >= 0);
|
||||
if (index >= _desserts.length)
|
||||
if (index >= _desserts.length) {
|
||||
return null;
|
||||
}
|
||||
final Dessert dessert = _desserts[index];
|
||||
return DataRow.byIndex(
|
||||
index: index,
|
||||
|
@ -134,8 +135,9 @@ class DessertDataSource extends DataTableSource {
|
|||
int get selectedRowCount => _selectedCount;
|
||||
|
||||
void _selectAll(bool? checked) {
|
||||
for (final Dessert dessert in _desserts)
|
||||
for (final Dessert dessert in _desserts) {
|
||||
dessert.selected = checked;
|
||||
}
|
||||
_selectedCount = checked! ? _desserts.length : 0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
|
@ -66,8 +66,9 @@ class _DateTimePicker extends StatelessWidget {
|
|||
firstDate: DateTime(2015, 8),
|
||||
lastDate: DateTime(2101),
|
||||
);
|
||||
if (picked != null && picked != selectedDate)
|
||||
if (picked != null && picked != selectedDate) {
|
||||
selectDate!(picked);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _selectTime(BuildContext context) async {
|
||||
|
@ -75,8 +76,9 @@ class _DateTimePicker extends StatelessWidget {
|
|||
context: context,
|
||||
initialTime: selectedTime!,
|
||||
);
|
||||
if (picked != null && picked != selectedTime)
|
||||
if (picked != null && picked != selectedTime) {
|
||||
selectTime!(picked);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -144,10 +144,11 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
|
|||
margin: EdgeInsets.zero,
|
||||
onDetailsPressed: () {
|
||||
_showDrawerContents = !_showDrawerContents;
|
||||
if (_showDrawerContents)
|
||||
if (_showDrawerContents) {
|
||||
_controller.reverse();
|
||||
else
|
||||
} else {
|
||||
_controller.forward();
|
||||
}
|
||||
},
|
||||
),
|
||||
MediaQuery.removePadding(
|
||||
|
|
|
@ -46,8 +46,9 @@ class DateTimeItem extends StatelessWidget {
|
|||
lastDate: date.add(const Duration(days: 30)),
|
||||
)
|
||||
.then((DateTime? value) {
|
||||
if (value != null)
|
||||
if (value != null) {
|
||||
onChanged(DateTime(value.year, value.month, value.day, time.hour, time.minute));
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
|
@ -73,8 +74,9 @@ class DateTimeItem extends StatelessWidget {
|
|||
initialTime: time,
|
||||
)
|
||||
.then((TimeOfDay? value) {
|
||||
if (value != null)
|
||||
if (value != null) {
|
||||
onChanged(DateTime(date.year, date.month, date.day, value.hour, value.minute));
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
|
@ -109,8 +111,9 @@ class FullScreenDialogDemoState extends State<FullScreenDialogDemo> {
|
|||
|
||||
Future<bool> _onWillPop() async {
|
||||
_saveNeeded = _hasLocation || _hasName || _saveNeeded;
|
||||
if (!_saveNeeded)
|
||||
if (!_saveNeeded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color);
|
||||
|
|
|
@ -118,8 +118,9 @@ class _GridPhotoViewerState extends State<GridPhotoViewer> with SingleTickerProv
|
|||
|
||||
void _handleOnScaleEnd(ScaleEndDetails details) {
|
||||
final double magnitude = details.velocity.pixelsPerSecond.distance;
|
||||
if (magnitude < _kMinFlingVelocity)
|
||||
if (magnitude < _kMinFlingVelocity) {
|
||||
return;
|
||||
}
|
||||
final Offset direction = details.velocity.pixelsPerSecond / magnitude;
|
||||
final double distance = (Offset.zero & context.size!).shortestSide;
|
||||
_flingAnimation = _controller.drive(Tween<Offset>(
|
||||
|
|
|
@ -222,10 +222,11 @@ class _LeaveBehindListItem extends StatelessWidget {
|
|||
key: ObjectKey(item),
|
||||
direction: dismissDirection,
|
||||
onDismissed: (DismissDirection direction) {
|
||||
if (direction == DismissDirection.endToStart)
|
||||
if (direction == DismissDirection.endToStart) {
|
||||
_handleArchive();
|
||||
else
|
||||
} else {
|
||||
_handleDelete();
|
||||
}
|
||||
},
|
||||
confirmDismiss: !confirmDismiss ? null : (DismissDirection dismissDirection) async {
|
||||
switch(dismissDirection) {
|
||||
|
|
|
@ -224,8 +224,9 @@ class _ListDemoState extends State<ListDemo> {
|
|||
}
|
||||
|
||||
Iterable<Widget> listTiles = items.map<Widget>((String item) => buildListTile(context, item));
|
||||
if (_showDividers != null)
|
||||
if (_showDividers != null) {
|
||||
listTiles = ListTile.divideTiles(context: context, tiles: listTiles);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
|
|
|
@ -42,16 +42,18 @@ class MenuDemoState extends State<MenuDemo> {
|
|||
}
|
||||
|
||||
void showMenuSelection(String value) {
|
||||
if (<String>[_simpleValue1, _simpleValue2, _simpleValue3].contains(value))
|
||||
if (<String>[_simpleValue1, _simpleValue2, _simpleValue3].contains(value)) {
|
||||
setState(() => _simpleValue = value);
|
||||
}
|
||||
showInSnackBar('You selected: $value');
|
||||
}
|
||||
|
||||
void showCheckedMenuSelections(String value) {
|
||||
if (_checkedValues.contains(value))
|
||||
if (_checkedValues.contains(value)) {
|
||||
_checkedValues.remove(value);
|
||||
else
|
||||
} else {
|
||||
_checkedValues.add(value);
|
||||
}
|
||||
|
||||
showInSnackBar('Checked $_checkedValues');
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ class OverscrollDemoState extends State<OverscrollDemo> {
|
|||
final Completer<void> completer = Completer<void>();
|
||||
Timer(const Duration(seconds: 3), () => completer.complete());
|
||||
return completer.future.then((_) {
|
||||
if (!mounted)
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: const Text('Refresh complete'),
|
||||
action: SnackBarAction(
|
||||
|
|
|
@ -13,8 +13,9 @@ class _PageSelector extends StatelessWidget {
|
|||
|
||||
void _handleArrowButtonPress(BuildContext context, int delta) {
|
||||
final TabController controller = DefaultTabController.of(context)!;
|
||||
if (!controller.indexIsChanging)
|
||||
if (!controller.indexIsChanging) {
|
||||
controller.animateTo((controller.index + delta).clamp(0, icons!.length - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -33,10 +33,11 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> with Sing
|
|||
curve: const Interval(0.0, 0.9, curve: Curves.fastOutSlowIn),
|
||||
reverseCurve: Curves.fastOutSlowIn,
|
||||
)..addStatusListener((AnimationStatus status) {
|
||||
if (status == AnimationStatus.dismissed)
|
||||
if (status == AnimationStatus.dismissed) {
|
||||
_controller.forward();
|
||||
else if (status == AnimationStatus.completed)
|
||||
} else if (status == AnimationStatus.completed) {
|
||||
_controller.reverse();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -68,8 +68,9 @@ class ScrollableTabsDemoState extends State<ScrollableTabsDemo> with SingleTicke
|
|||
}
|
||||
|
||||
Decoration? getIndicator() {
|
||||
if (!_customIndicator)
|
||||
if (!_customIndicator) {
|
||||
return const UnderlineTabIndicator();
|
||||
}
|
||||
|
||||
switch(_demoStyle) {
|
||||
case TabsDemoStyle.iconsAndText:
|
||||
|
|
|
@ -107,8 +107,9 @@ class _TabsFabDemoState extends State<TabsFabDemo> with SingleTickerProviderStat
|
|||
}
|
||||
|
||||
Widget? buildFloatingActionButton(_Page page) {
|
||||
if (!page.fabDefined)
|
||||
if (!page.fabDefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_extendedButtons) {
|
||||
return FloatingActionButton.extended(
|
||||
|
|
|
@ -112,36 +112,42 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
|
|||
|
||||
String? _validateName(String? value) {
|
||||
_formWasEdited = true;
|
||||
if (value!.isEmpty)
|
||||
if (value!.isEmpty) {
|
||||
return 'Name is required.';
|
||||
}
|
||||
final RegExp nameExp = RegExp(r'^[A-Za-z ]+$');
|
||||
if (!nameExp.hasMatch(value))
|
||||
if (!nameExp.hasMatch(value)) {
|
||||
return 'Please enter only alphabetical characters.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _validatePhoneNumber(String? value) {
|
||||
_formWasEdited = true;
|
||||
final RegExp phoneExp = RegExp(r'^\(\d\d\d\) \d\d\d\-\d\d\d\d$');
|
||||
if (!phoneExp.hasMatch(value!))
|
||||
if (!phoneExp.hasMatch(value!)) {
|
||||
return '(###) ###-#### - Enter a US phone number.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _validatePassword(String? value) {
|
||||
_formWasEdited = true;
|
||||
final FormFieldState<String> passwordField = _passwordFieldKey.currentState!;
|
||||
if (passwordField.value == null || passwordField.value!.isEmpty)
|
||||
if (passwordField.value == null || passwordField.value!.isEmpty) {
|
||||
return 'Please enter a password.';
|
||||
if (passwordField.value != value)
|
||||
}
|
||||
if (passwordField.value != value) {
|
||||
return "The passwords don't match";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<bool> _warnUserAboutInvalidData() async {
|
||||
final FormState? form = _formKey.currentState;
|
||||
if (form == null || !_formWasEdited || form.validate())
|
||||
if (form == null || !_formWasEdited || form.validate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final bool? result = await showDialog<bool>(
|
||||
context: context,
|
||||
|
@ -313,30 +319,35 @@ class _UsNumberTextInputFormatter extends TextInputFormatter {
|
|||
final StringBuffer newText = StringBuffer();
|
||||
if (newTextLength >= 1) {
|
||||
newText.write('(');
|
||||
if (newValue.selection.end >= 1)
|
||||
if (newValue.selection.end >= 1) {
|
||||
selectionIndex++;
|
||||
}
|
||||
}
|
||||
if (newTextLength >= 4) {
|
||||
final String value = newValue.text.substring(0, usedSubstringIndex = 3);
|
||||
newText.write('$value) ');
|
||||
if (newValue.selection.end >= 3)
|
||||
if (newValue.selection.end >= 3) {
|
||||
selectionIndex += 2;
|
||||
}
|
||||
}
|
||||
if (newTextLength >= 7) {
|
||||
final String value = newValue.text.substring(3, usedSubstringIndex = 6);
|
||||
newText.write('$value-');
|
||||
if (newValue.selection.end >= 6)
|
||||
if (newValue.selection.end >= 6) {
|
||||
selectionIndex++;
|
||||
}
|
||||
}
|
||||
if (newTextLength >= 11) {
|
||||
final String value = newValue.text.substring(6, usedSubstringIndex = 10);
|
||||
newText.write('$value ');
|
||||
if (newValue.selection.end >= 10)
|
||||
if (newValue.selection.end >= 10) {
|
||||
selectionIndex++;
|
||||
}
|
||||
}
|
||||
// Dump the rest.
|
||||
if (newTextLength >= usedSubstringIndex)
|
||||
if (newTextLength >= usedSubstringIndex) {
|
||||
newText.write(newValue.text.substring(usedSubstringIndex));
|
||||
}
|
||||
return TextEditingValue(
|
||||
text: newText.toString(),
|
||||
selection: TextSelection.collapsed(offset: selectionIndex),
|
||||
|
|
|
@ -418,10 +418,11 @@ class _RecipePageState extends State<RecipePage> {
|
|||
|
||||
void _toggleFavorite() {
|
||||
setState(() {
|
||||
if (_favoriteRecipes.contains(widget.recipe))
|
||||
if (_favoriteRecipes.contains(widget.recipe)) {
|
||||
_favoriteRecipes.remove(widget.recipe);
|
||||
else
|
||||
} else {
|
||||
_favoriteRecipes.add(widget.recipe);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -533,8 +533,9 @@ class ExtraProductsNumber extends StatelessWidget {
|
|||
}
|
||||
|
||||
Widget _buildOverflow(AppStateModel model, BuildContext context) {
|
||||
if (model.productsInCart.length <= 3)
|
||||
if (model.productsInCart.length <= 3) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
final int numOverflowProducts = _calculateOverflow(model);
|
||||
// Maximum of 99 so padding doesn't get messy.
|
||||
|
|
|
@ -148,8 +148,9 @@ class VideoPlayPause extends StatefulWidget {
|
|||
class _VideoPlayPauseState extends State<VideoPlayPause> {
|
||||
_VideoPlayPauseState() {
|
||||
listener = () {
|
||||
if (mounted)
|
||||
if (mounted) {
|
||||
setState(() { });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -241,16 +241,18 @@ class _BackdropState extends State<Backdrop> with SingleTickerProviderStateMixin
|
|||
}
|
||||
|
||||
void _handleDragEnd(DragEndDetails details) {
|
||||
if (_controller!.isAnimating || _controller!.status == AnimationStatus.completed)
|
||||
if (_controller!.isAnimating || _controller!.status == AnimationStatus.completed) {
|
||||
return;
|
||||
}
|
||||
|
||||
final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight;
|
||||
if (flingVelocity < 0.0)
|
||||
if (flingVelocity < 0.0) {
|
||||
_controller!.fling(velocity: math.max(2.0, -flingVelocity));
|
||||
else if (flingVelocity > 0.0)
|
||||
} else if (flingVelocity > 0.0) {
|
||||
_controller!.fling(velocity: math.min(-2.0, -flingVelocity));
|
||||
else
|
||||
} else {
|
||||
_controller!.fling(velocity: _controller!.value < 0.5 ? -2.0 : 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleFrontLayer() {
|
||||
|
|
|
@ -28,8 +28,9 @@ class ComponentDemoTabData {
|
|||
|
||||
@override
|
||||
bool operator==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is ComponentDemoTabData
|
||||
&& other.tabName == tabName
|
||||
&& other.description == description
|
||||
|
@ -67,8 +68,9 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
|
|||
|
||||
Future<void> _showApiDocumentation(BuildContext context) async {
|
||||
final String? url = demos![DefaultTabController.of(context)!.index].documentationUrl;
|
||||
if (url == null)
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Uri uri = Uri.parse(url);
|
||||
if (await canLaunchUrl(uri)) {
|
||||
|
|
|
@ -19,10 +19,12 @@ class GalleryDemoCategory {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other))
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
if (other.runtimeType != runtimeType)
|
||||
}
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is GalleryDemoCategory
|
||||
&& other.name == name
|
||||
&& other.icon == icon;
|
||||
|
|
|
@ -99,8 +99,9 @@ DropdownButton<String>(
|
|||
// null indicates the user didn't select a
|
||||
// new value.
|
||||
setState(() {
|
||||
if (newValue != null)
|
||||
if (newValue != null) {
|
||||
dropdownValue = newValue;
|
||||
}
|
||||
});
|
||||
},
|
||||
items: <String>['One', 'Two', 'Free', 'Four']
|
||||
|
|
|
@ -10,8 +10,9 @@ const String _kEndTag = '// END';
|
|||
Map<String?, String>? _exampleCode;
|
||||
|
||||
Future<String?> getExampleCode(String? tag, AssetBundle bundle) async {
|
||||
if (_exampleCode == null)
|
||||
if (_exampleCode == null) {
|
||||
await _parseExampleCode(bundle);
|
||||
}
|
||||
return _exampleCode![tag];
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,9 @@ class GalleryOptions {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is GalleryOptions
|
||||
&& other.themeMode == themeMode
|
||||
&& other.textScaleFactor == textScaleFactor
|
||||
|
@ -480,8 +481,9 @@ class GalleryOptionsPage extends StatelessWidget {
|
|||
List<Widget> _enabledDiagnosticItems() {
|
||||
// Boolean showFoo options with a value of null: don't display
|
||||
// the showFoo option at all.
|
||||
if (options == null)
|
||||
if (options == null) {
|
||||
return const <Widget>[];
|
||||
}
|
||||
|
||||
return <Widget>[
|
||||
const Divider(),
|
||||
|
|
|
@ -13,8 +13,9 @@ class GalleryTextScaleValue {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is GalleryTextScaleValue
|
||||
&& other.scale == scale
|
||||
&& other.label == label;
|
||||
|
@ -47,8 +48,9 @@ class GalleryVisualDensityValue {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
if (other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
return other is GalleryVisualDensityValue
|
||||
&& other.visualDensity == visualDensity
|
||||
&& other.label == label;
|
||||
|
|
|
@ -95,16 +95,18 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
|
|||
int currentPosition = 0;
|
||||
|
||||
for (final _HighlightSpan span in _spans) {
|
||||
if (currentPosition != span.start)
|
||||
if (currentPosition != span.start) {
|
||||
formattedText.add(TextSpan(text: _src!.substring(currentPosition, span.start)));
|
||||
}
|
||||
|
||||
formattedText.add(TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src!)));
|
||||
|
||||
currentPosition = span.end;
|
||||
}
|
||||
|
||||
if (currentPosition != _src!.length)
|
||||
if (currentPosition != _src!.length) {
|
||||
formattedText.add(TextSpan(text: _src!.substring(currentPosition, _src!.length)));
|
||||
}
|
||||
|
||||
return TextSpan(style: _style!.baseStyle, children: formattedText);
|
||||
} else {
|
||||
|
@ -149,8 +151,9 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
|
|||
endComment,
|
||||
));
|
||||
|
||||
if (eof)
|
||||
if (eof) {
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -260,17 +263,19 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
|
|||
_HighlightType? type;
|
||||
|
||||
String word = _scanner.lastMatch![0]!;
|
||||
if (word.startsWith('_'))
|
||||
if (word.startsWith('_')) {
|
||||
word = word.substring(1);
|
||||
}
|
||||
|
||||
if (_keywords.contains(word))
|
||||
if (_keywords.contains(word)) {
|
||||
type = _HighlightType.keyword;
|
||||
else if (_builtInTypes.contains(word))
|
||||
} else if (_builtInTypes.contains(word)) {
|
||||
type = _HighlightType.keyword;
|
||||
else if (_firstLetterIsUpperCase(word))
|
||||
} else if (_firstLetterIsUpperCase(word)) {
|
||||
type = _HighlightType.klass;
|
||||
else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1)))
|
||||
} else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1))) {
|
||||
type = _HighlightType.constant;
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
_spans.add(_HighlightSpan(
|
||||
|
@ -336,21 +341,22 @@ class _HighlightSpan {
|
|||
}
|
||||
|
||||
TextStyle? textStyle(SyntaxHighlighterStyle? style) {
|
||||
if (type == _HighlightType.number)
|
||||
if (type == _HighlightType.number) {
|
||||
return style!.numberStyle;
|
||||
else if (type == _HighlightType.comment)
|
||||
} else if (type == _HighlightType.comment) {
|
||||
return style!.commentStyle;
|
||||
else if (type == _HighlightType.keyword)
|
||||
} else if (type == _HighlightType.keyword) {
|
||||
return style!.keywordStyle;
|
||||
else if (type == _HighlightType.string)
|
||||
} else if (type == _HighlightType.string) {
|
||||
return style!.stringStyle;
|
||||
else if (type == _HighlightType.punctuation)
|
||||
} else if (type == _HighlightType.punctuation) {
|
||||
return style!.punctuationStyle;
|
||||
else if (type == _HighlightType.klass)
|
||||
} else if (type == _HighlightType.klass) {
|
||||
return style!.classStyle;
|
||||
else if (type == _HighlightType.constant)
|
||||
} else if (type == _HighlightType.constant) {
|
||||
return style!.constantStyle;
|
||||
else
|
||||
} else {
|
||||
return style!.baseStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ class UpdaterState extends State<Updater> {
|
|||
|
||||
final String? updateUrl = await widget.updateUrlFetcher();
|
||||
final bool? wantsUpdate = await showDialog<bool>(context: context, builder: _buildDialog);
|
||||
if (wantsUpdate != null && updateUrl != null && wantsUpdate)
|
||||
if (wantsUpdate != null && updateUrl != null && wantsUpdate) {
|
||||
launchUrl(Uri.parse(updateUrl));
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildDialog(BuildContext context) {
|
||||
|
|
|
@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
// We press the "1" and the "2" buttons and check that the display
|
||||
// reads "12".
|
||||
|
|
|
@ -9,8 +9,9 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
testWidgets('Flutter Gallery drawer item test', (WidgetTester tester) async {
|
||||
bool hasFeedback = false;
|
||||
|
|
|
@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
testWidgets('Flutter gallery button example code displays', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/6147
|
||||
|
|
|
@ -45,8 +45,9 @@ class TestAssetBundle extends AssetBundle {
|
|||
|
||||
@override
|
||||
Future<String> loadString(String key, { bool cache = true }) async {
|
||||
if (key == 'lib/gallery/example_code.dart')
|
||||
if (key == 'lib/gallery/example_code.dart') {
|
||||
return testCodeFile;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -51,10 +51,12 @@ Future<void> main() async {
|
|||
// Verify that _kUnsynchronizedDemos and _kSkippedDemos identify
|
||||
// demos that actually exist.
|
||||
final List<String> allDemoTitles = kAllGalleryDemos.map((GalleryDemo demo) => demo.title).toList();
|
||||
if (!Set<String>.from(allDemoTitles).containsAll(_kUnsynchronizedDemoTitles))
|
||||
if (!Set<String>.from(allDemoTitles).containsAll(_kUnsynchronizedDemoTitles)) {
|
||||
fail('Unrecognized demo titles in _kUnsynchronizedDemosTitles: $_kUnsynchronizedDemoTitles');
|
||||
if (!Set<String>.from(allDemoTitles).containsAll(_kSkippedDemoTitles))
|
||||
}
|
||||
if (!Set<String>.from(allDemoTitles).containsAll(_kSkippedDemoTitles)) {
|
||||
fail('Unrecognized demo names in _kSkippedDemoTitles: $_kSkippedDemoTitles');
|
||||
}
|
||||
|
||||
print('Starting app...');
|
||||
runApp(const GalleryApp(testMode: true));
|
||||
|
@ -66,8 +68,9 @@ Future<void> main() async {
|
|||
final Finder demoItem = find.text(demo.title);
|
||||
print('Scrolling to "${demo.title}"...');
|
||||
await controller.scrollIntoView(demoItem, alignment: 0.5);
|
||||
if (_kSkippedDemoTitles.contains(demo.title))
|
||||
if (_kSkippedDemoTitles.contains(demo.title)) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < 2; i += 1) {
|
||||
print('Tapping "${demo.title}"...');
|
||||
await controller.tap(demoItem); // Launch the demo
|
||||
|
@ -91,10 +94,12 @@ Future<void> main() async {
|
|||
final Finder backFinder = find.byElementPredicate(
|
||||
(Element element) {
|
||||
final Widget widget = element.widget;
|
||||
if (widget is Tooltip)
|
||||
if (widget is Tooltip) {
|
||||
return widget.message == 'Back';
|
||||
if (widget is CupertinoNavigationBarBackButton)
|
||||
}
|
||||
if (widget is CupertinoNavigationBarBackButton) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
description: 'Material or Cupertino back button',
|
||||
|
@ -122,11 +127,13 @@ class _LiveWidgetController extends LiveWidgetController {
|
|||
|
||||
/// Runs `finder` repeatedly until it finds one or more [Element]s.
|
||||
Future<Finder> _waitForElement(Finder finder) async {
|
||||
if (frameSync)
|
||||
if (frameSync) {
|
||||
await _waitUntilFrame(() => binding.transientCallbackCount == 0);
|
||||
}
|
||||
await _waitUntilFrame(() => finder.precache());
|
||||
if (frameSync)
|
||||
if (frameSync) {
|
||||
await _waitUntilFrame(() => binding.transientCallbackCount == 0);
|
||||
}
|
||||
return finder;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/5168
|
||||
testWidgets('Pesto appbar heroics', (WidgetTester tester) async {
|
||||
|
|
|
@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
testWidgets('Flutter Gallery app simple smoke test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
|
|
|
@ -40,8 +40,9 @@ void reportToStringError(String name, String route, int lineNumber, List<String>
|
|||
void verifyToStringOutput(String name, String route, String testString) {
|
||||
int lineNumber = 0;
|
||||
final List<String> lines = testString.split('\n');
|
||||
if (!testString.endsWith('\n'))
|
||||
if (!testString.endsWith('\n')) {
|
||||
reportToStringError(name, route, lines.length, lines, 'does not end with a line feed');
|
||||
}
|
||||
for (final String line in lines) {
|
||||
lineNumber += 1;
|
||||
if (line == '' && lineNumber != lines.length) {
|
||||
|
|
|
@ -12,8 +12,9 @@ Future<String> mockUpdateUrlFetcher() {
|
|||
|
||||
void main() {
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding)
|
||||
if (binding is LiveTestWidgetsFlutterBinding) {
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/5168
|
||||
testWidgets('update dialog', (WidgetTester tester) async {
|
||||
|
|
|
@ -23,8 +23,9 @@ Future<void> runDemos(List<String> demos, WidgetController controller) async {
|
|||
String? currentDemoCategory;
|
||||
|
||||
for (final String demo in demos) {
|
||||
if (kSkippedDemos.contains(demo))
|
||||
if (kSkippedDemos.contains(demo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String demoName = demo.substring(0, demo.indexOf('@'));
|
||||
final String demoCategory = demo.substring(demo.indexOf('@') + 1);
|
||||
|
|
|
@ -60,8 +60,9 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
|
|||
}
|
||||
|
||||
// Verify that the durations data is valid.
|
||||
if (durations.keys.isEmpty)
|
||||
if (durations.keys.isEmpty) {
|
||||
throw 'no "Start Transition" timeline events found';
|
||||
}
|
||||
final Map<String, int> unexpectedValueCounts = <String, int>{};
|
||||
durations.forEach((String routeName, List<int> values) {
|
||||
if (values.length != 2) {
|
||||
|
@ -83,8 +84,9 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
|
|||
while (eventIter.moveNext()) {
|
||||
final String eventName = eventIter.current['name'] as String;
|
||||
|
||||
if (!<String>['Start Transition', 'Frame'].contains(eventName))
|
||||
if (!<String>['Start Transition', 'Frame'].contains(eventName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String routeName = eventName == 'Start Transition'
|
||||
? (eventIter.current['args'] as Map<String, dynamic>)['to'] as String
|
||||
|
@ -114,8 +116,9 @@ Future<void> runDemos(List<String> demos, FlutterDriver driver) async {
|
|||
String? currentDemoCategory;
|
||||
|
||||
for (final String demo in demos) {
|
||||
if (kSkippedDemos.contains(demo))
|
||||
if (kSkippedDemos.contains(demo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String demoName = demo.substring(0, demo.indexOf('@'));
|
||||
final String demoCategory = demo.substring(demo.indexOf('@') + 1);
|
||||
|
@ -176,8 +179,9 @@ void main([List<String> args = const <String>[]]) {
|
|||
|
||||
// See _handleMessages() in transitions_perf.dart.
|
||||
_allDemos = List<String>.from(json.decode(await driver.requestData('demoNames')) as List<dynamic>);
|
||||
if (_allDemos.isEmpty)
|
||||
if (_allDemos.isEmpty) {
|
||||
throw 'no demo names found';
|
||||
}
|
||||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
|
|
|
@ -46,17 +46,19 @@ void diffActions(StringBuffer diffBuffer, Map<String, dynamic> originalEvent,
|
|||
final String originalActionName =
|
||||
getActionName(originalActionMasked, originalEvent['action'] as int);
|
||||
|
||||
if (synthesizedActionMasked != originalActionMasked)
|
||||
if (synthesizedActionMasked != originalActionMasked) {
|
||||
diffBuffer.write(
|
||||
'action (expected: $originalActionName actual: $synthesizedActionName) ');
|
||||
}
|
||||
|
||||
if (kPointerActions.contains(originalActionMasked) &&
|
||||
originalActionMasked == synthesizedActionMasked) {
|
||||
final int originalPointer = getPointerIdx(originalEvent['action'] as int);
|
||||
final int synthesizedPointer = getPointerIdx(synthesizedEvent['action'] as int);
|
||||
if (originalPointer != synthesizedPointer)
|
||||
if (originalPointer != synthesizedPointer) {
|
||||
diffBuffer.write(
|
||||
'pointerIdx (expected: $originalPointer actual: $synthesizedPointer action: $originalActionName ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,10 +124,12 @@ void diffMaps(
|
|||
return;
|
||||
}
|
||||
for (final String key in expected.keys) {
|
||||
if (excludeKeys.contains(key))
|
||||
if (excludeKeys.contains(key)) {
|
||||
continue;
|
||||
if (doublesApproximatelyMatch(expected[key], actual[key]))
|
||||
}
|
||||
if (doublesApproximatelyMatch(expected[key], actual[key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expected[key] != actual[key]) {
|
||||
diffBuffer.write(
|
||||
|
@ -154,10 +158,11 @@ String getActionName(int actionMasked, int action) {
|
|||
'BUTTON_PRESS',
|
||||
'BUTTON_RELEASE',
|
||||
];
|
||||
if (actionMasked < actionNames.length)
|
||||
if (actionMasked < actionNames.length) {
|
||||
return '${actionNames[actionMasked]}($action)';
|
||||
else
|
||||
} else {
|
||||
return 'ACTION_$actionMasked';
|
||||
}
|
||||
}
|
||||
|
||||
bool doublesApproximatelyMatch(dynamic a, dynamic b) =>
|
||||
|
|
|
@ -128,16 +128,19 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
|
||||
await viewChannel!.invokeMethod<void>('stopTouchEvents');
|
||||
|
||||
if (flutterViewEvents.length != embeddedViewEvents.length)
|
||||
if (flutterViewEvents.length != embeddedViewEvents.length) {
|
||||
return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
|
||||
}
|
||||
|
||||
final StringBuffer diff = StringBuffer();
|
||||
for (int i = 0; i < flutterViewEvents.length; ++i) {
|
||||
final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
|
||||
if (currentDiff.isEmpty)
|
||||
if (currentDiff.isEmpty) {
|
||||
continue;
|
||||
if (diff.isNotEmpty)
|
||||
}
|
||||
if (diff.isNotEmpty) {
|
||||
diff.write(', ');
|
||||
}
|
||||
diff.write(currentDiff);
|
||||
}
|
||||
return diff.toString();
|
||||
|
@ -201,8 +204,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
case 'onTouch':
|
||||
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
|
||||
flutterViewEvents.insert(0, map.cast<String, dynamic>());
|
||||
if (flutterViewEvents.length > kEventsBufferSize)
|
||||
if (flutterViewEvents.length > kEventsBufferSize) {
|
||||
flutterViewEvents.removeLast();
|
||||
}
|
||||
setState(() {});
|
||||
break;
|
||||
}
|
||||
|
@ -214,8 +218,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
case 'onTouch':
|
||||
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
|
||||
embeddedViewEvents.insert(0, map.cast<String, dynamic>());
|
||||
if (embeddedViewEvents.length > kEventsBufferSize)
|
||||
if (embeddedViewEvents.length > kEventsBufferSize) {
|
||||
embeddedViewEvents.removeLast();
|
||||
}
|
||||
setState(() {});
|
||||
break;
|
||||
}
|
||||
|
@ -223,9 +228,10 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
|
|||
}
|
||||
|
||||
Widget buildEventTile(BuildContext context, int index) {
|
||||
if (embeddedViewEvents.length > index)
|
||||
if (embeddedViewEvents.length > index) {
|
||||
return TouchEventDiff(
|
||||
flutterViewEvents[index], embeddedViewEvents[index]);
|
||||
}
|
||||
return Text(
|
||||
'Unmatched event, action: ${flutterViewEvents[index]['action']}');
|
||||
}
|
||||
|
|
|
@ -31,10 +31,11 @@ class _TestAppState extends State<TestApp> {
|
|||
|
||||
void _executeNextStep() {
|
||||
setState(() {
|
||||
if (_step < steps.length)
|
||||
if (_step < steps.length) {
|
||||
_result = steps[_step++]();
|
||||
else
|
||||
} else {
|
||||
_result = Future<TestStepResult>.value(TestStepResult.complete);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue