more UI-as-code (#35516)
This commit is contained in:
parent
d03aecab58
commit
df4bf453ab
@ -140,7 +140,7 @@ linter:
|
||||
- prefer_foreach
|
||||
# - prefer_function_declarations_over_variables # not yet tested
|
||||
- prefer_generic_function_type_aliases
|
||||
# - prefer_if_elements_to_conditional_expressions # not yet tested
|
||||
- prefer_if_elements_to_conditional_expressions
|
||||
- prefer_if_null_operators
|
||||
- prefer_initializing_formals
|
||||
- prefer_inlined_adds
|
||||
|
@ -208,23 +208,20 @@ class SampleChecker {
|
||||
|
||||
/// Computes the headers needed for each sample file.
|
||||
List<Line> get headers {
|
||||
if (_headers == null) {
|
||||
final List<String> buffer = <String>[];
|
||||
buffer.add('// generated code');
|
||||
buffer.add('import \'dart:async\';');
|
||||
buffer.add('import \'dart:convert\';');
|
||||
buffer.add('import \'dart:math\' as math;');
|
||||
buffer.add('import \'dart:typed_data\';');
|
||||
buffer.add('import \'dart:ui\' as ui;');
|
||||
buffer.add('import \'package:flutter_test/flutter_test.dart\';');
|
||||
for (File file in _listDartFiles(Directory(_defaultFlutterPackage))) {
|
||||
buffer.add('');
|
||||
buffer.add('// ${file.path}');
|
||||
buffer.add('import \'package:flutter/${path.basename(file.path)}\';');
|
||||
}
|
||||
_headers = buffer.map<Line>((String code) => Line(code)).toList();
|
||||
}
|
||||
return _headers;
|
||||
return _headers ??= <String>[
|
||||
'// generated code',
|
||||
"import 'dart:async';",
|
||||
"import 'dart:convert';",
|
||||
"import 'dart:math' as math;",
|
||||
"import 'dart:typed_data';",
|
||||
"import 'dart:ui' as ui;",
|
||||
"import 'package:flutter_test/flutter_test.dart';",
|
||||
for (File file in _listDartFiles(Directory(_defaultFlutterPackage))) ...<String>[
|
||||
'',
|
||||
'// ${file.path}',
|
||||
"import 'package:flutter/${path.basename(file.path)}';",
|
||||
],
|
||||
].map<Line>((String code) => Line(code)).toList();
|
||||
}
|
||||
|
||||
List<Line> _headers;
|
||||
|
@ -177,7 +177,7 @@ Future<void> _checkForTrailingSpaces() async {
|
||||
'*.dart', '*.cxx', '*.cpp', '*.cc', '*.c', '*.C', '*.h', '*.java', '*.mm', '*.m', '*.yml',
|
||||
];
|
||||
final EvalResult changedFilesResult = await _evalCommand(
|
||||
'git', <String>['diff', '-U0', '--no-color', '--name-only', commitRange, '--'] + fileTypes,
|
||||
'git', <String>['diff', '-U0', '--no-color', '--name-only', commitRange, '--', ...fileTypes],
|
||||
workingDirectory: flutterRoot,
|
||||
);
|
||||
if (changedFilesResult.stdout == null || changedFilesResult.stdout.trim().isEmpty) {
|
||||
@ -195,7 +195,8 @@ Future<void> _checkForTrailingSpaces() async {
|
||||
'--line-number',
|
||||
'--extended-regexp',
|
||||
r'[[:blank:]]$',
|
||||
] + changedFiles,
|
||||
...changedFiles,
|
||||
],
|
||||
workingDirectory: flutterRoot,
|
||||
failureMessage: '${red}Whitespace detected at the end of source code lines.$reset\nPlease remove:',
|
||||
expectNonZeroExit: true, // Just means a non-zero exit code is expected.
|
||||
|
@ -527,20 +527,16 @@ class ArchivePublisher {
|
||||
|
||||
// Search for any entries with the same hash and channel and remove them.
|
||||
final List<dynamic> releases = jsonData['releases'];
|
||||
final List<Map<String, dynamic>> prunedReleases = <Map<String, dynamic>>[];
|
||||
for (Map<String, dynamic> entry in releases) {
|
||||
if (entry['hash'] != newEntry['hash'] || entry['channel'] != newEntry['channel']) {
|
||||
prunedReleases.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
prunedReleases.add(newEntry);
|
||||
prunedReleases.sort((Map<String, dynamic> a, Map<String, dynamic> b) {
|
||||
jsonData['releases'] = <Map<String, dynamic>>[
|
||||
for (Map<String, dynamic> entry in releases)
|
||||
if (entry['hash'] != newEntry['hash'] || entry['channel'] != newEntry['channel'])
|
||||
entry,
|
||||
newEntry,
|
||||
]..sort((Map<String, dynamic> a, Map<String, dynamic> b) {
|
||||
final DateTime aDate = DateTime.parse(a['release_date']);
|
||||
final DateTime bDate = DateTime.parse(b['release_date']);
|
||||
return bDate.compareTo(aDate);
|
||||
});
|
||||
jsonData['releases'] = prunedReleases;
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
|
@ -184,17 +184,16 @@ Future<bq.BigqueryApi> _getBigqueryApi() async {
|
||||
|
||||
// Partition tool tests into two groups, see explanation on `_runToolCoverage`.
|
||||
List<List<String>> _partitionToolTests() {
|
||||
final List<String> pending = <String>[];
|
||||
final String toolTestDir = path.join(toolRoot, 'test');
|
||||
for (FileSystemEntity entity in Directory(toolTestDir).listSync(recursive: true)) {
|
||||
if (entity is File && entity.path.endsWith('_test.dart')) {
|
||||
final String relativePath = path.relative(entity.path, from: toolRoot);
|
||||
pending.add(relativePath);
|
||||
}
|
||||
}
|
||||
final List<String> pending = <String>[
|
||||
for (FileSystemEntity entity in Directory(toolTestDir).listSync(recursive: true))
|
||||
if (entity is File && entity.path.endsWith('_test.dart'))
|
||||
path.relative(entity.path, from: toolRoot),
|
||||
];
|
||||
|
||||
// Shuffle the tests to avoid giving an expensive test directory like
|
||||
// integration to a single run of tests.
|
||||
pending..shuffle();
|
||||
pending.shuffle();
|
||||
final int aboutHalf = pending.length ~/ 2;
|
||||
final List<String> groupA = pending.take(aboutHalf).toList();
|
||||
final List<String> groupB = pending.skip(aboutHalf).toList();
|
||||
@ -512,19 +511,20 @@ Future<void> _buildRunnerTest(
|
||||
bool enableFlutterToolAsserts = false,
|
||||
bq.TabledataResourceApi tableData,
|
||||
}) async {
|
||||
final List<String> args = <String>['run', 'build_runner', 'test', '--', useFlutterTestFormatter ? '-rjson' : '-rcompact', '-j1'];
|
||||
if (!hasColor) {
|
||||
args.add('--no-color');
|
||||
}
|
||||
if (testPath != null) {
|
||||
args.add(testPath);
|
||||
}
|
||||
final List<String> args = <String>[
|
||||
'run',
|
||||
'build_runner',
|
||||
'test',
|
||||
'--',
|
||||
if (useFlutterTestFormatter) '-rjson' else '-rcompact',
|
||||
'-j1',
|
||||
if (!hasColor) '--no-color',
|
||||
if (testPath != null) testPath,
|
||||
];
|
||||
final Map<String, String> pubEnvironment = <String, String>{
|
||||
'FLUTTER_ROOT': flutterRoot,
|
||||
if (Directory(pubCache).existsSync()) 'PUB_CACHE': pubCache,
|
||||
};
|
||||
if (Directory(pubCache).existsSync()) {
|
||||
pubEnvironment['PUB_CACHE'] = pubCache;
|
||||
}
|
||||
if (enableFlutterToolAsserts) {
|
||||
// If an existing env variable exists append to it, but only if
|
||||
// it doesn't appear to already include enable-asserts.
|
||||
@ -574,15 +574,17 @@ Future<void> _pubRunTest(
|
||||
bool enableFlutterToolAsserts = false,
|
||||
bq.TabledataResourceApi tableData,
|
||||
}) async {
|
||||
final List<String> args = <String>['run', 'test', useFlutterTestFormatter ? '-rjson' : '-rcompact', '-j1'];
|
||||
if (!hasColor)
|
||||
args.add('--no-color');
|
||||
if (testPath != null)
|
||||
args.add(testPath);
|
||||
final Map<String, String> pubEnvironment = <String, String>{};
|
||||
if (Directory(pubCache).existsSync()) {
|
||||
pubEnvironment['PUB_CACHE'] = pubCache;
|
||||
}
|
||||
final List<String> args = <String>[
|
||||
'run',
|
||||
'test',
|
||||
if (useFlutterTestFormatter) '-rjson' else '-rcompact',
|
||||
'-j1',
|
||||
if (!hasColor) '--no-color',
|
||||
if (testPath != null) testPath,
|
||||
];
|
||||
final Map<String, String> pubEnvironment = <String, String>{
|
||||
if (Directory(pubCache).existsSync()) 'PUB_CACHE': pubCache,
|
||||
};
|
||||
if (enableFlutterToolAsserts) {
|
||||
// If an existing env variable exists append to it, but only if
|
||||
// it doesn't appear to already include enable-asserts.
|
||||
|
@ -71,7 +71,7 @@ Future<Process> _run({@required Device device, @required List<String> command, @
|
||||
await inDirectory(appDir, () async {
|
||||
runner = await startProcess(
|
||||
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
||||
<String>['--suppress-analytics', '-d', device.deviceId] + command,
|
||||
<String>['--suppress-analytics', '-d', device.deviceId, ...command],
|
||||
isBot: false, // we just want to test the output, not have any debugging info
|
||||
);
|
||||
final StreamController<String> stdout = StreamController<String>.broadcast();
|
||||
|
@ -82,12 +82,11 @@ Future<Map<String, dynamic>> runTask(
|
||||
}
|
||||
|
||||
Future<VMIsolateRef> _connectToRunnerIsolate(Uri vmServiceUri) async {
|
||||
final List<String> pathSegments = <String>[];
|
||||
if (vmServiceUri.pathSegments.isNotEmpty) {
|
||||
final List<String> pathSegments = <String>[
|
||||
// Add authentication code.
|
||||
pathSegments.add(vmServiceUri.pathSegments[0]);
|
||||
}
|
||||
pathSegments.add('ws');
|
||||
if (vmServiceUri.pathSegments.isNotEmpty) vmServiceUri.pathSegments[0],
|
||||
'ws',
|
||||
];
|
||||
final String url = vmServiceUri.replace(scheme: 'ws', pathSegments:
|
||||
pathSegments).toString();
|
||||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
|
@ -65,12 +65,10 @@ abstract class _Benchmark {
|
||||
|
||||
Directory get directory;
|
||||
|
||||
List<String> get options {
|
||||
final List<String> result = <String>[ '--benchmark' ];
|
||||
if (watch)
|
||||
result.add('--watch');
|
||||
return result;
|
||||
}
|
||||
List<String> get options => <String>[
|
||||
'--benchmark',
|
||||
if (watch) '--watch',
|
||||
];
|
||||
|
||||
Future<double> execute(int iteration, int targetIterations) async {
|
||||
section('Analyze $title ${watch ? 'with watcher' : ''} - ${iteration + 1} / $targetIterations');
|
||||
|
@ -119,13 +119,11 @@ Future<void> saveCatalogScreenshots({
|
||||
String token, // Cloud storage authorization token.
|
||||
String prefix, // Prefix for all file names.
|
||||
}) async {
|
||||
final List<String> screenshots = <String>[];
|
||||
for (FileSystemEntity entity in directory.listSync()) {
|
||||
if (entity is File && entity.path.endsWith('.png')) {
|
||||
final File file = entity;
|
||||
screenshots.add(file.path);
|
||||
}
|
||||
}
|
||||
final List<String> screenshots = <String>[
|
||||
for (FileSystemEntity entity in directory.listSync())
|
||||
if (entity is File && entity.path.endsWith('.png'))
|
||||
entity.path,
|
||||
];
|
||||
|
||||
final List<String> largeNames = <String>[]; // Cloud storage names for the full res screenshots.
|
||||
final List<String> smallNames = <String>[]; // Likewise for the scaled down screenshots.
|
||||
|
@ -144,13 +144,9 @@ class AndroidSemanticsNode {
|
||||
}
|
||||
|
||||
/// Gets a list of [AndroidSemanticsActions] which are defined for the node.
|
||||
List<AndroidSemanticsAction> getActions() {
|
||||
final List<AndroidSemanticsAction> result = <AndroidSemanticsAction>[];
|
||||
for (int id in _values['actions']) {
|
||||
result.add(AndroidSemanticsAction.deserialize(id));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
List<AndroidSemanticsAction> getActions() => <AndroidSemanticsAction>[
|
||||
for (int id in _values['actions']) AndroidSemanticsAction.deserialize(id),
|
||||
];
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -34,7 +34,7 @@ class _ExampleWidgetState extends State<ExampleWidget> {
|
||||
});
|
||||
},
|
||||
),
|
||||
_pressed ? GeneratedWidget() : const SizedBox(),
|
||||
if (_pressed) GeneratedWidget() else const SizedBox(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -3,7 +3,7 @@ description: A test of Flutter integrating code generation.
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -179,26 +179,27 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> layers = <Widget>[
|
||||
Scaffold(
|
||||
appBar: AppBar(title: const Text('Tap a Card')),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0),
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: handleScrollNotification,
|
||||
child: ListView.custom(
|
||||
childrenDelegate: CardBuilder(
|
||||
cardModels: cardModels,
|
||||
onTapUp: handleTapUp,
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Scaffold(
|
||||
appBar: AppBar(title: const Text('Tap a Card')),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0),
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: handleScrollNotification,
|
||||
child: ListView.custom(
|
||||
childrenDelegate: CardBuilder(
|
||||
cardModels: cardModels,
|
||||
onTapUp: handleTapUp,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
for (MarkerType type in markers.keys)
|
||||
layers.add(Marker(type: type, position: markers[type]));
|
||||
return Stack(children: layers);
|
||||
for (MarkerType type in markers.keys)
|
||||
Marker(type: type, position: markers[type]),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,9 +556,6 @@ class _UnderlinesState extends State<Underlines> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> lines = <Widget>[_wrap(null)];
|
||||
for (TextDecorationStyle style in TextDecorationStyle.values)
|
||||
lines.add(_wrap(style));
|
||||
final Size size = MediaQuery.of(context).size;
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
@ -572,7 +569,10 @@ class _UnderlinesState extends State<Underlines> {
|
||||
vertical: size.height * 0.1,
|
||||
),
|
||||
child: ListBody(
|
||||
children: lines,
|
||||
children: <Widget>[
|
||||
_wrap(null),
|
||||
for (TextDecorationStyle style in TextDecorationStyle.values) _wrap(style),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -647,9 +647,6 @@ class _FallbackState extends State<Fallback> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> lines = <Widget>[];
|
||||
for (String font in androidFonts)
|
||||
lines.add(Text(multiScript, style: style.copyWith(fontFamily: font, fontSize: math.exp(_fontSize))));
|
||||
final Size size = MediaQuery.of(context).size;
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
@ -666,7 +663,16 @@ class _FallbackState extends State<Fallback> {
|
||||
),
|
||||
child: IntrinsicWidth(
|
||||
child: ListBody(
|
||||
children: lines,
|
||||
children: <Widget>[
|
||||
for (String font in androidFonts)
|
||||
Text(
|
||||
multiScript,
|
||||
style: style.copyWith(
|
||||
fontFamily: font,
|
||||
fontSize: math.exp(_fontSize),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -2,7 +2,7 @@ name: manual_tests
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.2.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -108,11 +108,12 @@ Future<void> main(List<String> arguments) async {
|
||||
createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml');
|
||||
cleanOutSnippets();
|
||||
|
||||
final List<String> dartdocBaseArgs = <String>['global', 'run'];
|
||||
if (args['checked']) {
|
||||
dartdocBaseArgs.add('-c');
|
||||
}
|
||||
dartdocBaseArgs.add('dartdoc');
|
||||
final List<String> dartdocBaseArgs = <String>[
|
||||
'global',
|
||||
'run',
|
||||
if (args['checked']) '-c',
|
||||
'dartdoc',
|
||||
];
|
||||
|
||||
// Verify which version of dartdoc we're using.
|
||||
final ProcessResult result = Process.runSync(
|
||||
@ -123,24 +124,17 @@ Future<void> main(List<String> arguments) async {
|
||||
);
|
||||
print('\n${result.stdout}flutter version: $version\n');
|
||||
|
||||
dartdocBaseArgs.add('--allow-tools');
|
||||
|
||||
if (args['json']) {
|
||||
dartdocBaseArgs.add('--json');
|
||||
}
|
||||
if (args['validate-links']) {
|
||||
dartdocBaseArgs.add('--validate-links');
|
||||
} else {
|
||||
dartdocBaseArgs.add('--no-validate-links');
|
||||
}
|
||||
dartdocBaseArgs.addAll(<String>['--link-to-source-excludes', '../../bin/cache',
|
||||
'--link-to-source-root', '../..',
|
||||
'--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%']);
|
||||
// Generate the documentation.
|
||||
// We don't need to exclude flutter_tools in this list because it's not in the
|
||||
// recursive dependencies of the package defined at dev/docs/pubspec.yaml
|
||||
final List<String> dartdocArgs = <String>[
|
||||
...dartdocBaseArgs,
|
||||
'--allow-tools',
|
||||
if (args['json']) '--json',
|
||||
if (args['validate-links']) '--validate-links' else '--no-validate-links',
|
||||
'--link-to-source-excludes', '../../bin/cache',
|
||||
'--link-to-source-root', '../..',
|
||||
'--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%',
|
||||
'--inject-html',
|
||||
'--header', 'styles.html',
|
||||
'--header', 'analytics.html',
|
||||
|
@ -52,10 +52,9 @@ class KeyData {
|
||||
|
||||
/// Parses the given JSON data and populates the data structure from it.
|
||||
KeyData.fromJson(Map<String, dynamic> contentMap) {
|
||||
data = <Key>[];
|
||||
for (String key in contentMap.keys) {
|
||||
data.add(Key.fromJsonMapEntry(key, contentMap[key]));
|
||||
}
|
||||
data = <Key>[
|
||||
for (String key in contentMap.keys) Key.fromJsonMapEntry(key, contentMap[key]),
|
||||
];
|
||||
}
|
||||
|
||||
/// Converts the data structure into a JSON structure that can be parsed by
|
||||
|
@ -3,7 +3,7 @@ description: Generates keycode source files from various resources.
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: 1.5.2
|
||||
|
@ -64,11 +64,9 @@ void main(List<String> args) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<FrameData> frames = <FrameData>[];
|
||||
for (String filePath in argResults.rest) {
|
||||
final FrameData data = interpretSvg(filePath);
|
||||
frames.add(data);
|
||||
}
|
||||
final List<FrameData> frames = <FrameData>[
|
||||
for (String filePath in argResults.rest) interpretSvg(filePath),
|
||||
];
|
||||
|
||||
final StringBuffer generatedSb = StringBuffer();
|
||||
|
||||
|
@ -6,7 +6,7 @@ author: Flutter Authors <flutter-dev@googlegroups.com>
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: 1.5.2
|
||||
|
@ -302,8 +302,9 @@ class CalcExpression {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
final List<ExpressionToken> outList = <ExpressionToken>[];
|
||||
outList.add(ResultToken(currentTermValue));
|
||||
final List<ExpressionToken> outList = <ExpressionToken>[
|
||||
ResultToken(currentTermValue),
|
||||
];
|
||||
return CalcExpression(outList, ExpressionState.Result);
|
||||
}
|
||||
|
||||
|
@ -54,33 +54,31 @@ class _ContactItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final List<Widget> columnChildren = lines.sublist(0, lines.length - 1).map<Widget>((String line) => Text(line)).toList();
|
||||
columnChildren.add(Text(lines.last, style: themeData.textTheme.caption));
|
||||
|
||||
final List<Widget> rowChildren = <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: columnChildren,
|
||||
),
|
||||
),
|
||||
];
|
||||
if (icon != null) {
|
||||
rowChildren.add(SizedBox(
|
||||
width: 72.0,
|
||||
child: IconButton(
|
||||
icon: Icon(icon),
|
||||
color: themeData.primaryColor,
|
||||
onPressed: onPressed,
|
||||
),
|
||||
));
|
||||
}
|
||||
return MergeSemantics(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: rowChildren,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
...lines.sublist(0, lines.length - 1).map<Widget>((String line) => Text(line)),
|
||||
Text(lines.last, style: themeData.textTheme.caption),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (icon != null)
|
||||
SizedBox(
|
||||
width: 72.0,
|
||||
child: IconButton(
|
||||
icon: Icon(icon),
|
||||
color: themeData.primaryColor,
|
||||
onPressed: onPressed,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -53,153 +53,148 @@ class _CupertinoAlertDemoState extends State<CupertinoAlertDemo> {
|
||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final List<Widget> stackChildren = <Widget>[
|
||||
CupertinoScrollbar(
|
||||
child: ListView(
|
||||
// Add more padding to the normal safe area.
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0)
|
||||
+ MediaQuery.of(context).padding,
|
||||
children: <Widget>[
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert'),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: CupertinoAlertDialog(
|
||||
title: const Text('Discard draft?'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Discard'),
|
||||
isDestructiveAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Discard');
|
||||
},
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
CupertinoScrollbar(
|
||||
child: ListView(
|
||||
// Add more padding to the normal safe area.
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 72.0)
|
||||
+ MediaQuery.of(context).padding,
|
||||
children: <Widget>[
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert'),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: CupertinoAlertDialog(
|
||||
title: const Text('Discard draft?'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Discard'),
|
||||
isDestructiveAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Discard');
|
||||
},
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Cancel'),
|
||||
isDefaultAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Cancel');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert with Title'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: CupertinoAlertDialog(
|
||||
title: const Text('Allow "Maps" to access your location while you are using the app?'),
|
||||
content: const Text('Your current location will be displayed on the map and used '
|
||||
'for directions, nearby search results, and estimated travel times.'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Don\'t Allow'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Disallow');
|
||||
},
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Allow'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Allow');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert with Buttons'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: const CupertinoDessertDialog(
|
||||
title: Text('Select Favorite Dessert'),
|
||||
content: Text('Please select your favorite type of dessert from the '
|
||||
'list below. Your selection will be used to customize the suggested '
|
||||
'list of eateries in your area.'),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert Buttons Only'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: const CupertinoDessertDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Action Sheet'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoActionSheet(
|
||||
context: context,
|
||||
child: CupertinoActionSheet(
|
||||
title: const Text('Favorite Dessert'),
|
||||
message: const Text('Please select the best dessert from the options below.'),
|
||||
actions: <Widget>[
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Profiteroles'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Profiteroles');
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Cannolis'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Cannolis');
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Trifle'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Trifle');
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
child: const Text('Cancel'),
|
||||
isDefaultAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Cancel');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert with Title'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: CupertinoAlertDialog(
|
||||
title: const Text('Allow "Maps" to access your location while you are using the app?'),
|
||||
content: const Text('Your current location will be displayed on the map and used '
|
||||
'for directions, nearby search results, and estimated travel times.'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Don\'t Allow'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Disallow');
|
||||
},
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
child: const Text('Allow'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Allow');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert with Buttons'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: const CupertinoDessertDialog(
|
||||
title: Text('Select Favorite Dessert'),
|
||||
content: Text('Please select your favorite type of dessert from the '
|
||||
'list below. Your selection will be used to customize the suggested '
|
||||
'list of eateries in your area.'),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Alert Buttons Only'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoDialog(
|
||||
context: context,
|
||||
child: const CupertinoDessertDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Padding(padding: EdgeInsets.all(8.0)),
|
||||
CupertinoButton.filled(
|
||||
child: const Text('Action Sheet'),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 36.0),
|
||||
onPressed: () {
|
||||
showDemoActionSheet(
|
||||
context: context,
|
||||
child: CupertinoActionSheet(
|
||||
title: const Text('Favorite Dessert'),
|
||||
message: const Text('Please select the best dessert from the options below.'),
|
||||
actions: <Widget>[
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Profiteroles'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Profiteroles');
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Cannolis'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Cannolis');
|
||||
},
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
child: const Text('Trifle'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Trifle');
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
child: const Text('Cancel'),
|
||||
isDefaultAction: true,
|
||||
onPressed: () {
|
||||
Navigator.pop(context, 'Cancel');
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (lastSelectedValue != null) {
|
||||
stackChildren.add(
|
||||
Positioned(
|
||||
bottom: 32.0,
|
||||
child: Text('You selected: $lastSelectedValue'),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: stackChildren,
|
||||
if (lastSelectedValue != null)
|
||||
Positioned(
|
||||
bottom: 32.0,
|
||||
child: Text('You selected: $lastSelectedValue'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -647,25 +647,21 @@ class Tab2ConversationRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
if (avatar != null)
|
||||
children.add(avatar);
|
||||
|
||||
final bool isSelf = avatar == null;
|
||||
children.add(
|
||||
Tab2ConversationBubble(
|
||||
text: text,
|
||||
color: isSelf
|
||||
? Tab2ConversationBubbleColor.blue
|
||||
: Tab2ConversationBubbleColor.gray,
|
||||
),
|
||||
);
|
||||
return SafeArea(
|
||||
child: Row(
|
||||
mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: isSelf ? CrossAxisAlignment.center : CrossAxisAlignment.end,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (avatar != null) avatar,
|
||||
Tab2ConversationBubble(
|
||||
text: text,
|
||||
color: isSelf
|
||||
? Tab2ConversationBubbleColor.blue
|
||||
: Tab2ConversationBubbleColor.gray,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -164,10 +164,9 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo>
|
||||
}
|
||||
|
||||
Widget _buildTransitionsStack() {
|
||||
final List<FadeTransition> transitions = <FadeTransition>[];
|
||||
|
||||
for (NavigationIconView view in _navigationViews)
|
||||
transitions.add(view.transition(_type, context));
|
||||
final List<FadeTransition> transitions = <FadeTransition>[
|
||||
for (NavigationIconView view in _navigationViews) view.transition(_type, context),
|
||||
];
|
||||
|
||||
// We want to have the newly animating (fading in) views on top.
|
||||
transitions.sort((FadeTransition a, FadeTransition b) {
|
||||
|
@ -262,89 +262,83 @@ class TravelDestinationContent extends StatelessWidget {
|
||||
final TextStyle titleStyle = theme.textTheme.headline.copyWith(color: Colors.white);
|
||||
final TextStyle descriptionStyle = theme.textTheme.subhead;
|
||||
|
||||
final List<Widget> children = <Widget>[
|
||||
// Photo and title.
|
||||
SizedBox(
|
||||
height: 184.0,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Positioned.fill(
|
||||
// In order to have the ink splash appear above the image, you
|
||||
// must use Ink.image. This allows the image to be painted as part
|
||||
// of the Material and display ink effects above it. Using a
|
||||
// standard Image will obscure the ink splash.
|
||||
child: Ink.image(
|
||||
image: AssetImage(destination.assetName, package: destination.assetPackage),
|
||||
fit: BoxFit.cover,
|
||||
child: Container(),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 16.0,
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
destination.title,
|
||||
style: titleStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Description and share/explore buttons.
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
|
||||
child: DefaultTextStyle(
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: descriptionStyle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Photo and title.
|
||||
SizedBox(
|
||||
height: 184.0,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
// three line description
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
destination.description,
|
||||
style: descriptionStyle.copyWith(color: Colors.black54),
|
||||
Positioned.fill(
|
||||
// In order to have the ink splash appear above the image, you
|
||||
// must use Ink.image. This allows the image to be painted as part
|
||||
// of the Material and display ink effects above it. Using a
|
||||
// standard Image will obscure the ink splash.
|
||||
child: Ink.image(
|
||||
image: AssetImage(destination.assetName, package: destination.assetPackage),
|
||||
fit: BoxFit.cover,
|
||||
child: Container(),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 16.0,
|
||||
left: 16.0,
|
||||
right: 16.0,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
destination.title,
|
||||
style: titleStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(destination.city),
|
||||
Text(destination.location),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
if (destination.type == CardDemoType.standard) {
|
||||
children.add(
|
||||
// share, explore buttons
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('SHARE', semanticsLabel: 'Share ${destination.title}'),
|
||||
textColor: Colors.amber.shade500,
|
||||
onPressed: () { print('pressed'); },
|
||||
// Description and share/explore buttons.
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
|
||||
child: DefaultTextStyle(
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: descriptionStyle,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// three line description
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Text(
|
||||
destination.description,
|
||||
style: descriptionStyle.copyWith(color: Colors.black54),
|
||||
),
|
||||
),
|
||||
Text(destination.city),
|
||||
Text(destination.location),
|
||||
],
|
||||
),
|
||||
FlatButton(
|
||||
child: Text('EXPLORE', semanticsLabel: 'Explore ${destination.title}'),
|
||||
textColor: Colors.amber.shade500,
|
||||
onPressed: () { print('pressed'); },
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children,
|
||||
if (destination.type == CardDemoType.standard)
|
||||
// share, explore buttons
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: Text('SHARE', semanticsLabel: 'Share ${destination.title}'),
|
||||
textColor: Colors.amber.shade500,
|
||||
onPressed: () { print('pressed'); },
|
||||
),
|
||||
FlatButton(
|
||||
child: Text('EXPLORE', semanticsLabel: 'Explore ${destination.title}'),
|
||||
textColor: Colors.amber.shade500,
|
||||
onPressed: () { print('pressed'); },
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -83,40 +83,36 @@ class _ChipsTile extends StatelessWidget {
|
||||
// Wraps a list of chips into a ListTile for display as a section in the demo.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> cardChildren = <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 16.0, bottom: 4.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(label, textAlign: TextAlign.start),
|
||||
),
|
||||
];
|
||||
if (children.isNotEmpty) {
|
||||
cardChildren.add(Wrap(
|
||||
children: children.map<Widget>((Widget chip) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: chip,
|
||||
);
|
||||
}).toList()));
|
||||
} else {
|
||||
final TextStyle textStyle = Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic);
|
||||
cardChildren.add(
|
||||
Semantics(
|
||||
container: true,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text('None', style: textStyle),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
return Card(
|
||||
semanticContainer: false,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: cardChildren,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 16.0, bottom: 4.0),
|
||||
alignment: Alignment.center,
|
||||
child: Text(label, textAlign: TextAlign.start),
|
||||
),
|
||||
if (children.isNotEmpty)
|
||||
Wrap(
|
||||
children: children.map<Widget>((Widget chip) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
child: chip,
|
||||
);
|
||||
}).toList(),
|
||||
)
|
||||
else
|
||||
Semantics(
|
||||
container: true,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
constraints: const BoxConstraints(minWidth: 48.0, minHeight: 48.0),
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text('None', style: Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -204,22 +204,23 @@ class _SearchDemoSearchDelegate extends SearchDelegate<int> {
|
||||
@override
|
||||
List<Widget> buildActions(BuildContext context) {
|
||||
return <Widget>[
|
||||
query.isEmpty
|
||||
? IconButton(
|
||||
tooltip: 'Voice Search',
|
||||
icon: const Icon(Icons.mic),
|
||||
onPressed: () {
|
||||
query = 'TODO: implement voice input';
|
||||
},
|
||||
)
|
||||
: IconButton(
|
||||
tooltip: 'Clear',
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () {
|
||||
query = '';
|
||||
showSuggestions(context);
|
||||
},
|
||||
),
|
||||
if (query.isEmpty)
|
||||
IconButton(
|
||||
tooltip: 'Voice Search',
|
||||
icon: const Icon(Icons.mic),
|
||||
onPressed: () {
|
||||
query = 'TODO: implement voice input';
|
||||
},
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
tooltip: 'Clear',
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () {
|
||||
query = '';
|
||||
showSuggestions(context);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ class TypographyDemo extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final TextTheme textTheme = Theme.of(context).textTheme;
|
||||
final List<Widget> styleItems = <Widget>[
|
||||
if (MediaQuery.of(context).size.width > 500.0)
|
||||
TextStyleItem(name: 'Display 4', style: textTheme.display4, text: 'Light 112sp'),
|
||||
TextStyleItem(name: 'Display 3', style: textTheme.display3, text: 'Regular 56sp'),
|
||||
TextStyleItem(name: 'Display 2', style: textTheme.display2, text: 'Regular 45sp'),
|
||||
TextStyleItem(name: 'Display 1', style: textTheme.display1, text: 'Regular 34sp'),
|
||||
@ -60,14 +62,6 @@ class TypographyDemo extends StatelessWidget {
|
||||
TextStyleItem(name: 'Button', style: textTheme.button, text: 'MEDIUM (ALL CAPS) 14sp'),
|
||||
];
|
||||
|
||||
if (MediaQuery.of(context).size.width > 500.0) {
|
||||
styleItems.insert(0, TextStyleItem(
|
||||
name: 'Display 4',
|
||||
style: textTheme.display4,
|
||||
text: 'Light 112sp',
|
||||
));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Typography')),
|
||||
body: SafeArea(
|
||||
|
@ -138,36 +138,31 @@ class _BackAppBar extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
width: 56.0,
|
||||
child: leading,
|
||||
),
|
||||
Expanded(
|
||||
child: title,
|
||||
),
|
||||
];
|
||||
|
||||
if (trailing != null) {
|
||||
children.add(
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
width: 56.0,
|
||||
child: trailing,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
return IconTheme.merge(
|
||||
data: theme.primaryIconTheme,
|
||||
child: DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.title,
|
||||
child: SizedBox(
|
||||
height: _kBackAppBarHeight,
|
||||
child: Row(children: children),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
width: 56.0,
|
||||
child: leading,
|
||||
),
|
||||
Expanded(
|
||||
child: title,
|
||||
),
|
||||
if (trailing != null)
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
width: 56.0,
|
||||
child: trailing,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -255,95 +250,88 @@ class _BackdropState extends State<Backdrop> with SingleTickerProviderStateMixin
|
||||
begin: RelativeRect.fromLTRB(0.0, constraints.biggest.height - _kFrontClosedHeight, 0.0, 0.0),
|
||||
end: const RelativeRect.fromLTRB(0.0, _kBackAppBarHeight, 0.0, 0.0),
|
||||
));
|
||||
|
||||
final List<Widget> layers = <Widget>[
|
||||
// Back layer
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
_BackAppBar(
|
||||
leading: widget.frontAction,
|
||||
title: _CrossFadeTransition(
|
||||
progress: _controller,
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child0: Semantics(namesRoute: true, child: widget.frontTitle),
|
||||
child1: Semantics(namesRoute: true, child: widget.backTitle),
|
||||
),
|
||||
trailing: IconButton(
|
||||
onPressed: _toggleFrontLayer,
|
||||
tooltip: 'Toggle options page',
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.close_menu,
|
||||
progress: _controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Visibility(
|
||||
child: widget.backLayer,
|
||||
visible: _controller.status != AnimationStatus.completed,
|
||||
maintainState: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Front layer
|
||||
PositionedTransition(
|
||||
rect: frontRelativeRect,
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return PhysicalShape(
|
||||
elevation: 12.0,
|
||||
color: Theme.of(context).canvasColor,
|
||||
clipper: ShapeBorderClipper(
|
||||
shape: BeveledRectangleBorder(
|
||||
borderRadius: _kFrontHeadingBevelRadius.transform(_controller.value),
|
||||
),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: _TappableWhileStatusIs(
|
||||
AnimationStatus.completed,
|
||||
controller: _controller,
|
||||
child: FadeTransition(
|
||||
opacity: _frontOpacity,
|
||||
child: widget.frontLayer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
// The front "heading" is a (typically transparent) widget that's stacked on
|
||||
// top of, and at the top of, the front layer. It adds support for dragging
|
||||
// the front layer up and down and for opening and closing the front layer
|
||||
// with a tap. It may obscure part of the front layer's topmost child.
|
||||
if (widget.frontHeading != null) {
|
||||
layers.add(
|
||||
PositionedTransition(
|
||||
rect: frontRelativeRect,
|
||||
child: ExcludeSemantics(
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: _toggleFrontLayer,
|
||||
onVerticalDragUpdate: _handleDragUpdate,
|
||||
onVerticalDragEnd: _handleDragEnd,
|
||||
child: widget.frontHeading,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
key: _backdropKey,
|
||||
children: layers,
|
||||
children: <Widget>[
|
||||
// Back layer
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
_BackAppBar(
|
||||
leading: widget.frontAction,
|
||||
title: _CrossFadeTransition(
|
||||
progress: _controller,
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child0: Semantics(namesRoute: true, child: widget.frontTitle),
|
||||
child1: Semantics(namesRoute: true, child: widget.backTitle),
|
||||
),
|
||||
trailing: IconButton(
|
||||
onPressed: _toggleFrontLayer,
|
||||
tooltip: 'Toggle options page',
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.close_menu,
|
||||
progress: _controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Visibility(
|
||||
child: widget.backLayer,
|
||||
visible: _controller.status != AnimationStatus.completed,
|
||||
maintainState: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Front layer
|
||||
PositionedTransition(
|
||||
rect: frontRelativeRect,
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return PhysicalShape(
|
||||
elevation: 12.0,
|
||||
color: Theme.of(context).canvasColor,
|
||||
clipper: ShapeBorderClipper(
|
||||
shape: BeveledRectangleBorder(
|
||||
borderRadius: _kFrontHeadingBevelRadius.transform(_controller.value),
|
||||
),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: _TappableWhileStatusIs(
|
||||
AnimationStatus.completed,
|
||||
controller: _controller,
|
||||
child: FadeTransition(
|
||||
opacity: _frontOpacity,
|
||||
child: widget.frontLayer,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// The front "heading" is a (typically transparent) widget that's stacked on
|
||||
// top of, and at the top of, the front layer. It adds support for dragging
|
||||
// the front layer up and down and for opening and closing the front layer
|
||||
// with a tap. It may obscure part of the front layer's topmost child.
|
||||
if (widget.frontHeading != null)
|
||||
PositionedTransition(
|
||||
rect: frontRelativeRect,
|
||||
child: ExcludeSemantics(
|
||||
child: Container(
|
||||
alignment: Alignment.topLeft,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: _toggleFrontLayer,
|
||||
onVerticalDragUpdate: _handleDragUpdate,
|
||||
onVerticalDragEnd: _handleDragEnd,
|
||||
child: widget.frontHeading,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -184,26 +184,6 @@ class _DemoItem extends StatelessWidget {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final bool isDark = theme.brightness == Brightness.dark;
|
||||
final double textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
|
||||
final List<Widget> titleChildren = <Widget>[
|
||||
Text(
|
||||
demo.title,
|
||||
style: theme.textTheme.subhead.copyWith(
|
||||
color: isDark ? Colors.white : const Color(0xFF202124),
|
||||
),
|
||||
),
|
||||
];
|
||||
if (demo.subtitle != null) {
|
||||
titleChildren.add(
|
||||
Text(
|
||||
demo.subtitle,
|
||||
style: theme.textTheme.body1.copyWith(
|
||||
color: isDark ? Colors.white : const Color(0xFF60646B)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return RawMaterialButton(
|
||||
padding: EdgeInsets.zero,
|
||||
splashColor: theme.primaryColor.withOpacity(0.12),
|
||||
@ -229,7 +209,21 @@ class _DemoItem extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: titleChildren,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
demo.title,
|
||||
style: theme.textTheme.subhead.copyWith(
|
||||
color: isDark ? Colors.white : const Color(0xFF202124),
|
||||
),
|
||||
),
|
||||
if (demo.subtitle != null)
|
||||
Text(
|
||||
demo.subtitle,
|
||||
style: theme.textTheme.body1.copyWith(
|
||||
color: isDark ? Colors.white : const Color(0xFF60646B)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 44.0),
|
||||
@ -294,11 +288,11 @@ class _GalleryHomeState extends State<GalleryHome> with SingleTickerProviderStat
|
||||
GalleryDemoCategory _category;
|
||||
|
||||
static Widget _topHomeLayout(Widget currentChild, List<Widget> previousChildren) {
|
||||
List<Widget> children = previousChildren;
|
||||
if (currentChild != null)
|
||||
children = children.toList()..add(currentChild);
|
||||
return Stack(
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
...previousChildren,
|
||||
if (currentChild != null) currentChild,
|
||||
],
|
||||
alignment: Alignment.topCenter,
|
||||
);
|
||||
}
|
||||
|
@ -425,13 +425,10 @@ class GalleryOptionsPage extends StatelessWidget {
|
||||
options.showPerformanceOverlay == null)
|
||||
return const <Widget>[];
|
||||
|
||||
final List<Widget> items = <Widget>[
|
||||
return <Widget>[
|
||||
const Divider(),
|
||||
const _Heading('Diagnostics'),
|
||||
];
|
||||
|
||||
if (options.showOffscreenLayersCheckerboard != null) {
|
||||
items.add(
|
||||
if (options.showOffscreenLayersCheckerboard != null)
|
||||
_BooleanItem(
|
||||
'Highlight offscreen layers',
|
||||
options.showOffscreenLayersCheckerboard,
|
||||
@ -439,10 +436,7 @@ class GalleryOptionsPage extends StatelessWidget {
|
||||
onOptionsChanged(options.copyWith(showOffscreenLayersCheckerboard: value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (options.showRasterCacheImagesCheckerboard != null) {
|
||||
items.add(
|
||||
if (options.showRasterCacheImagesCheckerboard != null)
|
||||
_BooleanItem(
|
||||
'Highlight raster cache images',
|
||||
options.showRasterCacheImagesCheckerboard,
|
||||
@ -450,10 +444,7 @@ class GalleryOptionsPage extends StatelessWidget {
|
||||
onOptionsChanged(options.copyWith(showRasterCacheImagesCheckerboard: value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
if (options.showPerformanceOverlay != null) {
|
||||
items.add(
|
||||
if (options.showPerformanceOverlay != null)
|
||||
_BooleanItem(
|
||||
'Show performance overlay',
|
||||
options.showPerformanceOverlay,
|
||||
@ -461,10 +452,7 @@ class GalleryOptionsPage extends StatelessWidget {
|
||||
onOptionsChanged(options.copyWith(showPerformanceOverlay: value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -85,12 +85,7 @@ class AdaptiveContainer extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
List<String> _initNames() {
|
||||
final List<String> names = <String>[];
|
||||
for (int i = 0; i < 30; i++)
|
||||
names.add('Item $i');
|
||||
return names;
|
||||
}
|
||||
List<String> _initNames() => List<String>.generate(30, (int i) => 'Item $i');
|
||||
|
||||
final List<String> _kNames = _initNames();
|
||||
|
||||
|
@ -94,25 +94,20 @@ class _StyledTextDemoState extends State<StyledTextDemo> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> lines = _kNameLines
|
||||
.map<Widget>((List<String> nameAndText) => _toText(nameAndText[0], nameAndText[1]))
|
||||
.toList();
|
||||
|
||||
final List<Widget> children = <Widget>[];
|
||||
for (Widget line in lines) {
|
||||
children.add(line);
|
||||
if (line != lines.last)
|
||||
children.add(SpeakerSeparator());
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: _handleTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Column(
|
||||
children: children,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _kNameLines
|
||||
.map<Widget>((List<String> nameAndText) => _toText(nameAndText[0], nameAndText[1]))
|
||||
.expand((Widget line) => <Widget>[
|
||||
line,
|
||||
SpeakerSeparator(),
|
||||
])
|
||||
.toList()..removeLast(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -174,16 +174,17 @@ class CupertinoAlertDialog extends StatelessWidget {
|
||||
final ScrollController actionScrollController;
|
||||
|
||||
Widget _buildContent(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (title != null || content != null) {
|
||||
final Widget titleSection = _CupertinoAlertContentSection(
|
||||
title: title,
|
||||
content: content,
|
||||
scrollController: scrollController,
|
||||
);
|
||||
children.add(Flexible(flex: 3, child: titleSection));
|
||||
}
|
||||
final List<Widget> children = <Widget>[
|
||||
if (title != null || content != null)
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: _CupertinoAlertContentSection(
|
||||
title: title,
|
||||
content: content,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
color: CupertinoDynamicColor.resolve(_kDialogColor, context),
|
||||
@ -597,16 +598,10 @@ class _RenderCupertinoDialog extends RenderBox {
|
||||
}
|
||||
|
||||
@override
|
||||
List<DiagnosticsNode> debugDescribeChildren() {
|
||||
final List<DiagnosticsNode> value = <DiagnosticsNode>[];
|
||||
if (contentSection != null) {
|
||||
value.add(contentSection.toDiagnosticsNode(name: 'content'));
|
||||
}
|
||||
if (actionsSection != null) {
|
||||
value.add(actionsSection.toDiagnosticsNode(name: 'actions'));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[
|
||||
if (contentSection != null) contentSection.toDiagnosticsNode(name: 'content'),
|
||||
if (actionsSection != null) actionsSection.toDiagnosticsNode(name: 'actions'),
|
||||
];
|
||||
|
||||
@override
|
||||
double computeMinIntrinsicWidth(double height) {
|
||||
|
@ -90,8 +90,6 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> stacked = <Widget>[];
|
||||
|
||||
Widget paddedContent = widget.child;
|
||||
|
||||
final MediaQueryData existingMediaQuery = MediaQuery.of(context);
|
||||
@ -157,44 +155,40 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
|
||||
);
|
||||
}
|
||||
|
||||
// The main content being at the bottom is added to the stack first.
|
||||
stacked.add(PrimaryScrollController(
|
||||
controller: _primaryScrollController,
|
||||
child: paddedContent,
|
||||
));
|
||||
|
||||
if (widget.navigationBar != null) {
|
||||
stacked.add(Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
child: MediaQuery(
|
||||
data: existingMediaQuery.copyWith(textScaleFactor: 1),
|
||||
child: widget.navigationBar,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Add a touch handler the size of the status bar on top of all contents
|
||||
// to handle scroll to top by status bar taps.
|
||||
stacked.add(Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
height: existingMediaQuery.padding.top,
|
||||
child: GestureDetector(
|
||||
excludeFromSemantics: true,
|
||||
onTap: _handleStatusBarTap,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? CupertinoTheme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
child: Stack(
|
||||
children: stacked,
|
||||
children: <Widget>[
|
||||
// The main content being at the bottom is added to the stack first.
|
||||
PrimaryScrollController(
|
||||
controller: _primaryScrollController,
|
||||
child: paddedContent,
|
||||
),
|
||||
if (widget.navigationBar != null)
|
||||
Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
child: MediaQuery(
|
||||
data: existingMediaQuery.copyWith(textScaleFactor: 1),
|
||||
child: widget.navigationBar,
|
||||
),
|
||||
),
|
||||
// Add a touch handler the size of the status bar on top of all contents
|
||||
// to handle scroll to top by status bar taps.
|
||||
Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
height: existingMediaQuery.padding.top,
|
||||
child: GestureDetector(
|
||||
excludeFromSemantics: true,
|
||||
onTap: _handleStatusBarTap,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -346,8 +346,6 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> stacked = <Widget>[];
|
||||
|
||||
final MediaQueryData existingMediaQuery = MediaQuery.of(context);
|
||||
MediaQueryData newMediaQuery = MediaQuery.of(context);
|
||||
|
||||
@ -397,36 +395,33 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
|
||||
),
|
||||
);
|
||||
|
||||
// The main content being at the bottom is added to the stack first.
|
||||
stacked.add(content);
|
||||
|
||||
stacked.add(
|
||||
MediaQuery(
|
||||
data: existingMediaQuery.copyWith(textScaleFactor: 1),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
// Override the tab bar's currentIndex to the current tab and hook in
|
||||
// our own listener to update the [_controller.currentIndex] on top of a possibly user
|
||||
// provided callback.
|
||||
child: widget.tabBar.copyWith(
|
||||
currentIndex: _controller.index,
|
||||
onTap: (int newIndex) {
|
||||
_controller.index = newIndex;
|
||||
// Chain the user's original callback.
|
||||
if (widget.tabBar.onTap != null)
|
||||
widget.tabBar.onTap(newIndex);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.backgroundColor ?? CupertinoTheme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
child: Stack(
|
||||
children: stacked,
|
||||
children: <Widget>[
|
||||
// The main content being at the bottom is added to the stack first.
|
||||
content,
|
||||
MediaQuery(
|
||||
data: existingMediaQuery.copyWith(textScaleFactor: 1),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
// Override the tab bar's currentIndex to the current tab and hook in
|
||||
// our own listener to update the [_controller.currentIndex] on top of a possibly user
|
||||
// provided callback.
|
||||
child: widget.tabBar.copyWith(
|
||||
currentIndex: _controller.index,
|
||||
onTap: (int newIndex) {
|
||||
_controller.index = newIndex;
|
||||
// Chain the user's original callback.
|
||||
if (widget.tabBar.onTap != null)
|
||||
widget.tabBar.onTap(newIndex);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -730,44 +730,38 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
valueListenable: _effectiveController,
|
||||
child: editableText,
|
||||
builder: (BuildContext context, TextEditingValue text, Widget child) {
|
||||
final List<Widget> rowChildren = <Widget>[];
|
||||
|
||||
// Insert a prefix at the front if the prefix visibility mode matches
|
||||
// the current text state.
|
||||
if (_showPrefixWidget(text)) {
|
||||
rowChildren.add(widget.prefix);
|
||||
}
|
||||
|
||||
final List<Widget> stackChildren = <Widget>[];
|
||||
|
||||
// In the middle part, stack the placeholder on top of the main EditableText
|
||||
// if needed.
|
||||
if (widget.placeholder != null && text.text.isEmpty) {
|
||||
stackChildren.add(
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Padding(
|
||||
padding: widget.padding,
|
||||
child: Text(
|
||||
widget.placeholder,
|
||||
maxLines: widget.maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: placeholderStyle,
|
||||
textAlign: widget.textAlign,
|
||||
),
|
||||
),
|
||||
return Row(children: <Widget>[
|
||||
// Insert a prefix at the front if the prefix visibility mode matches
|
||||
// the current text state.
|
||||
if (_showPrefixWidget(text)) widget.prefix,
|
||||
// In the middle part, stack the placeholder on top of the main EditableText
|
||||
// if needed.
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
if (widget.placeholder != null && text.text.isEmpty)
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: Padding(
|
||||
padding: widget.padding,
|
||||
child: Text(
|
||||
widget.placeholder,
|
||||
maxLines: widget.maxLines,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: placeholderStyle,
|
||||
textAlign: widget.textAlign,
|
||||
),
|
||||
),
|
||||
),
|
||||
child,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
rowChildren.add(Expanded(child: Stack(children: stackChildren..add(child))));
|
||||
|
||||
// First add the explicit suffix if the suffix visibility mode matches.
|
||||
if (_showSuffixWidget(text)) {
|
||||
rowChildren.add(widget.suffix);
|
||||
// Otherwise, try to show a clear button if its visibility mode matches.
|
||||
} else if (_showClearButton(text)) {
|
||||
rowChildren.add(
|
||||
),
|
||||
// First add the explicit suffix if the suffix visibility mode matches.
|
||||
if (_showSuffixWidget(text))
|
||||
widget.suffix
|
||||
// Otherwise, try to show a clear button if its visibility mode matches.
|
||||
else if (_showClearButton(text))
|
||||
GestureDetector(
|
||||
key: _clearGlobalKey,
|
||||
onTap: widget.enabled ?? true ? () {
|
||||
@ -787,10 +781,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Row(children: rowChildren);
|
||||
]);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -547,9 +547,9 @@ class FlutterError extends Error with DiagnosticableTreeMixin implements Asserti
|
||||
'(one line) summary description of the problem that was '
|
||||
'detected.'
|
||||
),
|
||||
DiagnosticsProperty<FlutterError>('Malformed', this, expandableValue: true, showSeparator: false, style: DiagnosticsTreeStyle.whitespace),
|
||||
ErrorDescription('\nThe malformed error has ${summaries.length} summaries.'),
|
||||
];
|
||||
message.add(DiagnosticsProperty<FlutterError>('Malformed', this, expandableValue: true, showSeparator: false, style: DiagnosticsTreeStyle.whitespace));
|
||||
message.add(ErrorDescription('\nThe malformed error has ${summaries.length} summaries.'));
|
||||
int i = 1;
|
||||
for (DiagnosticsNode summary in summaries) {
|
||||
message.add(DiagnosticsProperty<DiagnosticsNode>('Summary $i', summary, expandableValue : true));
|
||||
|
@ -552,10 +552,13 @@ class _AppBarState extends State<AppBar> {
|
||||
child: appBar,
|
||||
),
|
||||
),
|
||||
widget.bottomOpacity == 1.0 ? widget.bottom : Opacity(
|
||||
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
|
||||
child: widget.bottom,
|
||||
),
|
||||
if (widget.bottomOpacity == 1.0)
|
||||
widget.bottom
|
||||
else
|
||||
Opacity(
|
||||
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
|
||||
child: widget.bottom,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -303,22 +303,9 @@ class AlertDialog extends StatelessWidget {
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final DialogTheme dialogTheme = DialogTheme.of(context);
|
||||
final List<Widget> children = <Widget>[];
|
||||
String label = semanticLabel;
|
||||
|
||||
if (title != null) {
|
||||
children.add(Padding(
|
||||
padding: titlePadding ?? EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
|
||||
child: DefaultTextStyle(
|
||||
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title,
|
||||
child: Semantics(
|
||||
child: title,
|
||||
namesRoute: true,
|
||||
container: true,
|
||||
),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
String label = semanticLabel;
|
||||
if (title == null) {
|
||||
switch (theme.platform) {
|
||||
case TargetPlatform.iOS:
|
||||
label = semanticLabel;
|
||||
@ -329,29 +316,38 @@ class AlertDialog extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
children.add(Flexible(
|
||||
child: Padding(
|
||||
padding: contentPadding,
|
||||
child: DefaultTextStyle(
|
||||
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if (actions != null) {
|
||||
children.add(ButtonBar(
|
||||
children: actions,
|
||||
));
|
||||
}
|
||||
|
||||
Widget dialogChild = IntrinsicWidth(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (title != null)
|
||||
Padding(
|
||||
padding: titlePadding ?? EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
|
||||
child: DefaultTextStyle(
|
||||
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title,
|
||||
child: Semantics(
|
||||
child: title,
|
||||
namesRoute: true,
|
||||
container: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (content != null)
|
||||
Flexible(
|
||||
child: Padding(
|
||||
padding: contentPadding,
|
||||
child: DefaultTextStyle(
|
||||
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (actions != null)
|
||||
ButtonBar(
|
||||
children: actions,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@ -584,20 +580,10 @@ class SimpleDialog extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
final List<Widget> body = <Widget>[];
|
||||
String label = semanticLabel;
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
if (title != null) {
|
||||
body.add(Padding(
|
||||
padding: titlePadding,
|
||||
child: DefaultTextStyle(
|
||||
style: theme.textTheme.title,
|
||||
child: Semantics(namesRoute: true, child: title),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
String label = semanticLabel;
|
||||
if (title == null) {
|
||||
switch (theme.platform) {
|
||||
case TargetPlatform.iOS:
|
||||
label = semanticLabel;
|
||||
@ -608,15 +594,6 @@ class SimpleDialog extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
body.add(Flexible(
|
||||
child: SingleChildScrollView(
|
||||
padding: contentPadding,
|
||||
child: ListBody(children: children),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Widget dialogChild = IntrinsicWidth(
|
||||
stepWidth: 56.0,
|
||||
child: ConstrainedBox(
|
||||
@ -624,7 +601,23 @@ class SimpleDialog extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: body,
|
||||
children: <Widget>[
|
||||
if (title != null)
|
||||
Padding(
|
||||
padding: titlePadding,
|
||||
child: DefaultTextStyle(
|
||||
style: theme.textTheme.title,
|
||||
child: Semantics(namesRoute: true, child: title),
|
||||
),
|
||||
),
|
||||
if (children != null)
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
padding: contentPadding,
|
||||
child: ListBody(children: children),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -951,9 +951,10 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
widget.isExpanded
|
||||
? Expanded(child: innerItemsWidget)
|
||||
: innerItemsWidget,
|
||||
if (widget.isExpanded)
|
||||
Expanded(child: innerItemsWidget)
|
||||
else
|
||||
innerItemsWidget,
|
||||
IconTheme(
|
||||
data: IconThemeData(
|
||||
color: _iconColor,
|
||||
|
@ -48,27 +48,26 @@ class GridTile extends StatelessWidget {
|
||||
if (header == null && footer == null)
|
||||
return child;
|
||||
|
||||
final List<Widget> children = <Widget>[
|
||||
Positioned.fill(
|
||||
child: child,
|
||||
),
|
||||
];
|
||||
if (header != null) {
|
||||
children.add(Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
child: header,
|
||||
));
|
||||
}
|
||||
if (footer != null) {
|
||||
children.add(Positioned(
|
||||
left: 0.0,
|
||||
bottom: 0.0,
|
||||
right: 0.0,
|
||||
child: footer,
|
||||
));
|
||||
}
|
||||
return Stack(children: children);
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Positioned.fill(
|
||||
child: child,
|
||||
),
|
||||
if (header != null)
|
||||
Positioned(
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
child: header,
|
||||
),
|
||||
if (footer != null)
|
||||
Positioned(
|
||||
left: 0.0,
|
||||
bottom: 0.0,
|
||||
right: 0.0,
|
||||
child: footer,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,60 +62,17 @@ class GridTileBar extends StatelessWidget {
|
||||
if (backgroundColor != null)
|
||||
decoration = BoxDecoration(color: backgroundColor);
|
||||
|
||||
final List<Widget> children = <Widget>[];
|
||||
final EdgeInsetsDirectional padding = EdgeInsetsDirectional.only(
|
||||
start: leading != null ? 8.0 : 16.0,
|
||||
end: trailing != null ? 8.0 : 16.0,
|
||||
);
|
||||
|
||||
if (leading != null)
|
||||
children.add(Padding(padding: const EdgeInsetsDirectional.only(end: 8.0), child: leading));
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ThemeData darkTheme = ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
accentColor: theme.accentColor,
|
||||
accentColorBrightness: theme.accentColorBrightness,
|
||||
);
|
||||
if (title != null && subtitle != null) {
|
||||
children.add(
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
DefaultTextStyle(
|
||||
style: darkTheme.textTheme.subhead,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: title,
|
||||
),
|
||||
DefaultTextStyle(
|
||||
style: darkTheme.textTheme.caption,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
} else if (title != null || subtitle != null) {
|
||||
children.add(
|
||||
Expanded(
|
||||
child: DefaultTextStyle(
|
||||
style: darkTheme.textTheme.subhead,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: title ?? subtitle,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (trailing != null)
|
||||
children.add(Padding(padding: const EdgeInsetsDirectional.only(start: 8.0), child: trailing));
|
||||
|
||||
return Container(
|
||||
padding: padding,
|
||||
decoration: decoration,
|
||||
@ -126,7 +83,42 @@ class GridTileBar extends StatelessWidget {
|
||||
data: const IconThemeData(color: Colors.white),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (leading != null)
|
||||
Padding(padding: const EdgeInsetsDirectional.only(end: 8.0), child: leading),
|
||||
if (title != null && subtitle != null)
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
DefaultTextStyle(
|
||||
style: darkTheme.textTheme.subhead,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: title,
|
||||
),
|
||||
DefaultTextStyle(
|
||||
style: darkTheme.textTheme.caption,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else if (title != null || subtitle != null)
|
||||
Expanded(
|
||||
child: DefaultTextStyle(
|
||||
style: darkTheme.textTheme.subhead,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: title ?? subtitle,
|
||||
),
|
||||
),
|
||||
if (trailing != null)
|
||||
Padding(padding: const EdgeInsetsDirectional.only(start: 8.0), child: trailing),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -433,17 +433,13 @@ class InkResponse extends StatefulWidget {
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
final List<String> gestures = <String>[];
|
||||
if (onTap != null)
|
||||
gestures.add('tap');
|
||||
if (onDoubleTap != null)
|
||||
gestures.add('double tap');
|
||||
if (onLongPress != null)
|
||||
gestures.add('long press');
|
||||
if (onTapDown != null)
|
||||
gestures.add('tap down');
|
||||
if (onTapCancel != null)
|
||||
gestures.add('tap cancel');
|
||||
final List<String> gestures = <String>[
|
||||
if (onTap != null) 'tap',
|
||||
if (onDoubleTap != null) 'double tap',
|
||||
if (onLongPress != null) 'long press',
|
||||
if (onTapDown != null) 'tap down',
|
||||
if (onTapCancel != null) 'tap cancel',
|
||||
];
|
||||
properties.add(IterableProperty<String>('gestures', gestures, ifEmpty: '<none>'));
|
||||
properties.add(DiagnosticsProperty<bool>('containedInkWell', containedInkWell, level: DiagnosticLevel.fine));
|
||||
properties.add(DiagnosticsProperty<BoxShape>(
|
||||
|
@ -3145,79 +3145,44 @@ class InputDecoration {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> description = <String>[];
|
||||
if (icon != null)
|
||||
description.add('icon: $icon');
|
||||
if (labelText != null)
|
||||
description.add('labelText: "$labelText"');
|
||||
if (helperText != null)
|
||||
description.add('helperText: "$helperText"');
|
||||
if (hintText != null)
|
||||
description.add('hintText: "$hintText"');
|
||||
if (hintMaxLines != null)
|
||||
description.add('hintMaxLines: "$hintMaxLines"');
|
||||
if (errorText != null)
|
||||
description.add('errorText: "$errorText"');
|
||||
if (errorStyle != null)
|
||||
description.add('errorStyle: "$errorStyle"');
|
||||
if (errorMaxLines != null)
|
||||
description.add('errorMaxLines: "$errorMaxLines"');
|
||||
if (hasFloatingPlaceholder == false)
|
||||
description.add('hasFloatingPlaceholder: false');
|
||||
if (isDense ?? false)
|
||||
description.add('isDense: $isDense');
|
||||
if (contentPadding != null)
|
||||
description.add('contentPadding: $contentPadding');
|
||||
if (isCollapsed)
|
||||
description.add('isCollapsed: $isCollapsed');
|
||||
if (prefixIcon != null)
|
||||
description.add('prefixIcon: $prefixIcon');
|
||||
if (prefix != null)
|
||||
description.add('prefix: $prefix');
|
||||
if (prefixText != null)
|
||||
description.add('prefixText: $prefixText');
|
||||
if (prefixStyle != null)
|
||||
description.add('prefixStyle: $prefixStyle');
|
||||
if (suffixIcon != null)
|
||||
description.add('suffixIcon: $suffixIcon');
|
||||
if (suffix != null)
|
||||
description.add('suffix: $suffix');
|
||||
if (suffixText != null)
|
||||
description.add('suffixText: $suffixText');
|
||||
if (suffixStyle != null)
|
||||
description.add('suffixStyle: $suffixStyle');
|
||||
if (counter != null)
|
||||
description.add('counter: $counter');
|
||||
if (counterText != null)
|
||||
description.add('counterText: $counterText');
|
||||
if (counterStyle != null)
|
||||
description.add('counterStyle: $counterStyle');
|
||||
if (filled == true) // filled == null same as filled == false
|
||||
description.add('filled: true');
|
||||
if (fillColor != null)
|
||||
description.add('fillColor: $fillColor');
|
||||
if (focusColor != null)
|
||||
description.add('focusColor: $focusColor');
|
||||
if (hoverColor != null)
|
||||
description.add('hoverColor: $hoverColor');
|
||||
if (errorBorder != null)
|
||||
description.add('errorBorder: $errorBorder');
|
||||
if (focusedBorder != null)
|
||||
description.add('focusedBorder: $focusedBorder');
|
||||
if (focusedErrorBorder != null)
|
||||
description.add('focusedErrorBorder: $focusedErrorBorder');
|
||||
if (disabledBorder != null)
|
||||
description.add('disabledBorder: $disabledBorder');
|
||||
if (enabledBorder != null)
|
||||
description.add('enabledBorder: $enabledBorder');
|
||||
if (border != null)
|
||||
description.add('border: $border');
|
||||
if (!enabled)
|
||||
description.add('enabled: false');
|
||||
if (semanticCounterText != null)
|
||||
description.add('semanticCounterText: $semanticCounterText');
|
||||
if (alignLabelWithHint != null)
|
||||
description.add('alignLabelWithHint: $alignLabelWithHint');
|
||||
final List<String> description = <String>[
|
||||
if (icon != null) 'icon: $icon',
|
||||
if (labelText != null) 'labelText: "$labelText"',
|
||||
if (helperText != null) 'helperText: "$helperText"',
|
||||
if (hintText != null) 'hintText: "$hintText"',
|
||||
if (hintMaxLines != null) 'hintMaxLines: "$hintMaxLines"',
|
||||
if (errorText != null) 'errorText: "$errorText"',
|
||||
if (errorStyle != null) 'errorStyle: "$errorStyle"',
|
||||
if (errorMaxLines != null) 'errorMaxLines: "$errorMaxLines"',
|
||||
if (hasFloatingPlaceholder == false) 'hasFloatingPlaceholder: false',
|
||||
if (isDense ?? false) 'isDense: $isDense',
|
||||
if (contentPadding != null) 'contentPadding: $contentPadding',
|
||||
if (isCollapsed) 'isCollapsed: $isCollapsed',
|
||||
if (prefixIcon != null) 'prefixIcon: $prefixIcon',
|
||||
if (prefix != null) 'prefix: $prefix',
|
||||
if (prefixText != null) 'prefixText: $prefixText',
|
||||
if (prefixStyle != null) 'prefixStyle: $prefixStyle',
|
||||
if (suffixIcon != null) 'suffixIcon: $suffixIcon',
|
||||
if (suffix != null) 'suffix: $suffix',
|
||||
if (suffixText != null) 'suffixText: $suffixText',
|
||||
if (suffixStyle != null) 'suffixStyle: $suffixStyle',
|
||||
if (counter != null) 'counter: $counter',
|
||||
if (counterText != null) 'counterText: $counterText',
|
||||
if (counterStyle != null) 'counterStyle: $counterStyle',
|
||||
if (filled == true) 'filled: true', // filled == null same as filled == false
|
||||
if (fillColor != null) 'fillColor: $fillColor',
|
||||
if (focusColor != null) 'focusColor: $focusColor',
|
||||
if (hoverColor != null) 'hoverColor: $hoverColor',
|
||||
if (errorBorder != null) 'errorBorder: $errorBorder',
|
||||
if (focusedBorder != null) 'focusedBorder: $focusedBorder',
|
||||
if (focusedErrorBorder != null) 'focusedErrorBorder: $focusedErrorBorder',
|
||||
if (disabledBorder != null) 'disabledBorder: $disabledBorder',
|
||||
if (enabledBorder != null) 'enabledBorder: $enabledBorder',
|
||||
if (border != null) 'border: $border',
|
||||
if (!enabled) 'enabled: false',
|
||||
if (semanticCounterText != null) 'semanticCounterText: $semanticCounterText',
|
||||
if (alignLabelWithHint != null) 'alignLabelWithHint: $alignLabelWithHint',
|
||||
];
|
||||
return 'InputDecoration(${description.join(', ')})';
|
||||
}
|
||||
}
|
||||
|
@ -538,13 +538,6 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
// We use the layout builder to constrain the cross-axis size of dragging child widgets.
|
||||
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
|
||||
final List<Widget> wrappedChildren = <Widget>[];
|
||||
if (widget.header != null) {
|
||||
wrappedChildren.add(widget.header);
|
||||
}
|
||||
for (int i = 0; i < widget.children.length; i += 1) {
|
||||
wrappedChildren.add(_wrap(widget.children[i], i, constraints));
|
||||
}
|
||||
const Key endWidgetKey = Key('DraggableList - End Widget');
|
||||
Widget finalDropArea;
|
||||
switch (widget.scrollDirection) {
|
||||
@ -564,25 +557,19 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T
|
||||
);
|
||||
break;
|
||||
}
|
||||
if (widget.reverse) {
|
||||
wrappedChildren.insert(0, _wrap(
|
||||
finalDropArea,
|
||||
widget.children.length,
|
||||
constraints),
|
||||
);
|
||||
} else {
|
||||
wrappedChildren.add(_wrap(
|
||||
finalDropArea,
|
||||
widget.children.length,
|
||||
constraints),
|
||||
);
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: widget.scrollDirection,
|
||||
child: _buildContainerForScrollDirection(children: wrappedChildren),
|
||||
padding: widget.padding,
|
||||
controller: _scrollController,
|
||||
reverse: widget.reverse,
|
||||
child: _buildContainerForScrollDirection(
|
||||
children: <Widget>[
|
||||
if (widget.reverse) _wrap(finalDropArea, widget.children.length, constraints),
|
||||
if (widget.header != null) widget.header,
|
||||
for (int i = 0; i < widget.children.length; i += 1) _wrap(widget.children[i], i, constraints),
|
||||
if (!widget.reverse) _wrap(finalDropArea, widget.children.length, constraints),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -749,46 +749,40 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (_previousController.status != AnimationStatus.dismissed) {
|
||||
if (_isExtendedFloatingActionButton(_previousChild)) {
|
||||
children.add(FadeTransition(
|
||||
opacity: _previousScaleAnimation,
|
||||
child: _previousChild,
|
||||
));
|
||||
} else {
|
||||
children.add(ScaleTransition(
|
||||
scale: _previousScaleAnimation,
|
||||
child: RotationTransition(
|
||||
turns: _previousRotationAnimation,
|
||||
child: _previousChild,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (_isExtendedFloatingActionButton(widget.child)) {
|
||||
children.add(ScaleTransition(
|
||||
scale: _extendedCurrentScaleAnimation,
|
||||
child: FadeTransition(
|
||||
opacity: _currentScaleAnimation,
|
||||
child: widget.child,
|
||||
),
|
||||
));
|
||||
} else {
|
||||
children.add(ScaleTransition(
|
||||
scale: _currentScaleAnimation,
|
||||
child: RotationTransition(
|
||||
turns: _currentRotationAnimation,
|
||||
child: widget.child,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
return Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (_previousController.status != AnimationStatus.dismissed)
|
||||
if (_isExtendedFloatingActionButton(_previousChild))
|
||||
FadeTransition(
|
||||
opacity: _previousScaleAnimation,
|
||||
child: _previousChild,
|
||||
)
|
||||
else
|
||||
ScaleTransition(
|
||||
scale: _previousScaleAnimation,
|
||||
child: RotationTransition(
|
||||
turns: _previousRotationAnimation,
|
||||
child: _previousChild,
|
||||
),
|
||||
),
|
||||
if (_isExtendedFloatingActionButton(widget.child))
|
||||
ScaleTransition(
|
||||
scale: _extendedCurrentScaleAnimation,
|
||||
child: FadeTransition(
|
||||
opacity: _currentScaleAnimation,
|
||||
child: widget.child,
|
||||
),
|
||||
)
|
||||
else
|
||||
ScaleTransition(
|
||||
scale: _currentScaleAnimation,
|
||||
child: RotationTransition(
|
||||
turns: _currentRotationAnimation,
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -288,28 +288,6 @@ class SnackBar extends StatelessWidget {
|
||||
final bool isFloatingSnackBar = snackBarBehavior == SnackBarBehavior.floating;
|
||||
final double snackBarPadding = isFloatingSnackBar ? 16.0 : 24.0;
|
||||
|
||||
final List<Widget> children = <Widget>[
|
||||
SizedBox(width: snackBarPadding),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: _singleLineVerticalPadding),
|
||||
child: DefaultTextStyle(
|
||||
style: contentTextStyle,
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
if (action != null) {
|
||||
children.add(ButtonTheme(
|
||||
textTheme: ButtonTextTheme.accent,
|
||||
minWidth: 64.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: snackBarPadding),
|
||||
child: action,
|
||||
));
|
||||
} else {
|
||||
children.add(SizedBox(width: snackBarPadding));
|
||||
}
|
||||
final CurvedAnimation heightAnimation = CurvedAnimation(parent: animation, curve: _snackBarHeightCurve);
|
||||
final CurvedAnimation fadeInAnimation = CurvedAnimation(parent: animation, curve: _snackBarFadeInCurve);
|
||||
final CurvedAnimation fadeOutAnimation = CurvedAnimation(
|
||||
@ -322,8 +300,28 @@ class SnackBar extends StatelessWidget {
|
||||
top: false,
|
||||
bottom: !isFloatingSnackBar,
|
||||
child: Row(
|
||||
children: children,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
SizedBox(width: snackBarPadding),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: _singleLineVerticalPadding),
|
||||
child: DefaultTextStyle(
|
||||
style: contentTextStyle,
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (action != null)
|
||||
ButtonTheme(
|
||||
textTheme: ButtonTextTheme.accent,
|
||||
minWidth: 64.0,
|
||||
padding: EdgeInsets.symmetric(horizontal: snackBarPadding),
|
||||
child: action,
|
||||
)
|
||||
else
|
||||
SizedBox(width: snackBarPadding),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -480,32 +480,27 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
Widget _buildHeaderText(int index) {
|
||||
final List<Widget> children = <Widget>[
|
||||
AnimatedDefaultTextStyle(
|
||||
style: _titleStyle(index),
|
||||
duration: kThemeAnimationDuration,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
child: widget.steps[index].title,
|
||||
),
|
||||
];
|
||||
|
||||
if (widget.steps[index].subtitle != null)
|
||||
children.add(
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 2.0),
|
||||
child: AnimatedDefaultTextStyle(
|
||||
style: _subtitleStyle(index),
|
||||
duration: kThemeAnimationDuration,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
child: widget.steps[index].subtitle,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
AnimatedDefaultTextStyle(
|
||||
style: _titleStyle(index),
|
||||
duration: kThemeAnimationDuration,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
child: widget.steps[index].title,
|
||||
),
|
||||
if (widget.steps[index].subtitle != null)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 2.0),
|
||||
child: AnimatedDefaultTextStyle(
|
||||
style: _subtitleStyle(index),
|
||||
duration: kThemeAnimationDuration,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
child: widget.steps[index].subtitle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -577,46 +572,39 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
Widget _buildVertical() {
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||
children.add(
|
||||
Column(
|
||||
key: _keys[i],
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: widget.steps[i].state != StepState.disabled ? () {
|
||||
// In the vertical case we need to scroll to the newly tapped
|
||||
// step.
|
||||
Scrollable.ensureVisible(
|
||||
_keys[i].currentContext,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: kThemeAnimationDuration,
|
||||
);
|
||||
|
||||
if (widget.onStepTapped != null)
|
||||
widget.onStepTapped(i);
|
||||
} : null,
|
||||
child: _buildVerticalHeader(i),
|
||||
),
|
||||
_buildVerticalBody(i),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return ListView(
|
||||
shrinkWrap: true,
|
||||
physics: widget.physics,
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
for (int i = 0; i < widget.steps.length; i += 1)
|
||||
Column(
|
||||
key: _keys[i],
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: widget.steps[i].state != StepState.disabled ? () {
|
||||
// In the vertical case we need to scroll to the newly tapped
|
||||
// step.
|
||||
Scrollable.ensureVisible(
|
||||
_keys[i].currentContext,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
duration: kThemeAnimationDuration,
|
||||
);
|
||||
|
||||
if (widget.onStepTapped != null)
|
||||
widget.onStepTapped(i);
|
||||
} : null,
|
||||
child: _buildVerticalHeader(i),
|
||||
),
|
||||
_buildVerticalBody(i),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHorizontal() {
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
for (int i = 0; i < widget.steps.length; i += 1) {
|
||||
children.add(
|
||||
final List<Widget> children = <Widget>[
|
||||
for (int i = 0; i < widget.steps.length; i += 1) ...<Widget>[
|
||||
InkResponse(
|
||||
onTap: widget.steps[i].state != StepState.disabled ? () {
|
||||
if (widget.onStepTapped != null)
|
||||
@ -637,10 +625,7 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (!_isLast(i)) {
|
||||
children.add(
|
||||
if (!_isLast(i))
|
||||
Expanded(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
@ -648,9 +633,8 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
|
@ -40,17 +40,13 @@ class _TextSelectionToolbar extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> items = <Widget>[];
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
|
||||
if (handleCut != null)
|
||||
items.add(FlatButton(child: Text(localizations.cutButtonLabel), onPressed: handleCut));
|
||||
if (handleCopy != null)
|
||||
items.add(FlatButton(child: Text(localizations.copyButtonLabel), onPressed: handleCopy));
|
||||
if (handlePaste != null)
|
||||
items.add(FlatButton(child: Text(localizations.pasteButtonLabel), onPressed: handlePaste,));
|
||||
if (handleSelectAll != null)
|
||||
items.add(FlatButton(child: Text(localizations.selectAllButtonLabel), onPressed: handleSelectAll));
|
||||
final List<Widget> items = <Widget>[
|
||||
if (handleCut != null) FlatButton(child: Text(localizations.cutButtonLabel), onPressed: handleCut),
|
||||
if (handleCopy != null) FlatButton(child: Text(localizations.copyButtonLabel), onPressed: handleCopy),
|
||||
if (handlePaste != null) FlatButton(child: Text(localizations.pasteButtonLabel), onPressed: handlePaste),
|
||||
if (handleSelectAll != null) FlatButton(child: Text(localizations.selectAllButtonLabel), onPressed: handleSelectAll),
|
||||
];
|
||||
|
||||
// If there is no option available, build an empty widget.
|
||||
if (items.isEmpty) {
|
||||
|
@ -541,12 +541,13 @@ _TimePickerHeaderFormat _buildHeaderFormat(
|
||||
_TimePickerHeaderFragment fragment2,
|
||||
_TimePickerHeaderFragment fragment3,
|
||||
}) {
|
||||
final List<_TimePickerHeaderFragment> fragments = <_TimePickerHeaderFragment>[fragment1];
|
||||
if (fragment2 != null) {
|
||||
fragments.add(fragment2);
|
||||
if (fragment3 != null)
|
||||
fragments.add(fragment3);
|
||||
}
|
||||
final List<_TimePickerHeaderFragment> fragments = <_TimePickerHeaderFragment>[
|
||||
fragment1,
|
||||
if (fragment2 != null) ...<_TimePickerHeaderFragment>[
|
||||
fragment2,
|
||||
if (fragment3 != null) fragment3,
|
||||
],
|
||||
];
|
||||
return _TimePickerHeaderPiece(pivotIndex, fragments, bottomMargin: bottomMargin);
|
||||
}
|
||||
|
||||
@ -1336,50 +1337,41 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
List<_TappableLabel> _build24HourInnerRing(TextTheme textTheme) {
|
||||
final List<_TappableLabel> labels = <_TappableLabel>[];
|
||||
for (TimeOfDay timeOfDay in _amHours) {
|
||||
labels.add(_buildTappableLabel(
|
||||
List<_TappableLabel> _build24HourInnerRing(TextTheme textTheme) => <_TappableLabel>[
|
||||
for (TimeOfDay timeOfDay in _amHours)
|
||||
_buildTappableLabel(
|
||||
textTheme,
|
||||
timeOfDay.hour,
|
||||
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
|
||||
() {
|
||||
_selectHour(timeOfDay.hour);
|
||||
},
|
||||
));
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
List<_TappableLabel> _build24HourOuterRing(TextTheme textTheme) {
|
||||
final List<_TappableLabel> labels = <_TappableLabel>[];
|
||||
for (TimeOfDay timeOfDay in _pmHours) {
|
||||
labels.add(_buildTappableLabel(
|
||||
List<_TappableLabel> _build24HourOuterRing(TextTheme textTheme) => <_TappableLabel>[
|
||||
for (TimeOfDay timeOfDay in _pmHours)
|
||||
_buildTappableLabel(
|
||||
textTheme,
|
||||
timeOfDay.hour,
|
||||
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
|
||||
() {
|
||||
_selectHour(timeOfDay.hour);
|
||||
},
|
||||
));
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
List<_TappableLabel> _build12HourOuterRing(TextTheme textTheme) {
|
||||
final List<_TappableLabel> labels = <_TappableLabel>[];
|
||||
for (TimeOfDay timeOfDay in _amHours) {
|
||||
labels.add(_buildTappableLabel(
|
||||
List<_TappableLabel> _build12HourOuterRing(TextTheme textTheme) => <_TappableLabel>[
|
||||
for (TimeOfDay timeOfDay in _amHours)
|
||||
_buildTappableLabel(
|
||||
textTheme,
|
||||
timeOfDay.hour,
|
||||
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
|
||||
() {
|
||||
_selectHour(timeOfDay.hour);
|
||||
},
|
||||
));
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
List<_TappableLabel> _buildMinutes(TextTheme textTheme) {
|
||||
const List<TimeOfDay> _minuteMarkerValues = <TimeOfDay>[
|
||||
@ -1397,18 +1389,17 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
TimeOfDay(hour: 0, minute: 55),
|
||||
];
|
||||
|
||||
final List<_TappableLabel> labels = <_TappableLabel>[];
|
||||
for (TimeOfDay timeOfDay in _minuteMarkerValues) {
|
||||
labels.add(_buildTappableLabel(
|
||||
textTheme,
|
||||
timeOfDay.minute,
|
||||
localizations.formatMinute(timeOfDay),
|
||||
() {
|
||||
_selectMinute(timeOfDay.minute);
|
||||
},
|
||||
));
|
||||
}
|
||||
return labels;
|
||||
return <_TappableLabel>[
|
||||
for (TimeOfDay timeOfDay in _minuteMarkerValues)
|
||||
_buildTappableLabel(
|
||||
textTheme,
|
||||
timeOfDay.minute,
|
||||
localizations.formatMinute(timeOfDay),
|
||||
() {
|
||||
_selectMinute(timeOfDay.minute);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -134,71 +134,63 @@ class _AccountDetailsState extends State<_AccountDetails> with SingleTickerProvi
|
||||
assert(debugCheckHasMaterialLocalizations(context));
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (widget.accountName != null) {
|
||||
final Widget accountNameLine = LayoutId(
|
||||
id: _AccountDetailsLayout.accountName,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.body2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: widget.accountName,
|
||||
),
|
||||
),
|
||||
);
|
||||
children.add(accountNameLine);
|
||||
}
|
||||
|
||||
if (widget.accountEmail != null) {
|
||||
final Widget accountEmailLine = LayoutId(
|
||||
id: _AccountDetailsLayout.accountEmail,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.body1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: widget.accountEmail,
|
||||
),
|
||||
),
|
||||
);
|
||||
children.add(accountEmailLine);
|
||||
}
|
||||
if (widget.onTap != null) {
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
final Widget dropDownIcon = LayoutId(
|
||||
id: _AccountDetailsLayout.dropdownIcon,
|
||||
child: Semantics(
|
||||
container: true,
|
||||
button: true,
|
||||
onTap: widget.onTap,
|
||||
child: SizedBox(
|
||||
height: _kAccountDetailsHeight,
|
||||
width: _kAccountDetailsHeight,
|
||||
child: Center(
|
||||
child: Transform.rotate(
|
||||
angle: _animation.value * math.pi,
|
||||
child: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
color: widget.arrowColor,
|
||||
semanticLabel: widget.isOpen
|
||||
? localizations.hideAccountsLabel
|
||||
: localizations.showAccountsLabel,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
children.add(dropDownIcon);
|
||||
}
|
||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||
|
||||
Widget accountDetails = CustomMultiChildLayout(
|
||||
delegate: _AccountDetailsLayout(
|
||||
textDirection: Directionality.of(context),
|
||||
),
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (widget.accountName != null)
|
||||
LayoutId(
|
||||
id: _AccountDetailsLayout.accountName,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.body2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: widget.accountName,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.accountEmail != null)
|
||||
LayoutId(
|
||||
id: _AccountDetailsLayout.accountEmail,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: DefaultTextStyle(
|
||||
style: theme.primaryTextTheme.body1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: widget.accountEmail,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.onTap != null)
|
||||
LayoutId(
|
||||
id: _AccountDetailsLayout.dropdownIcon,
|
||||
child: Semantics(
|
||||
container: true,
|
||||
button: true,
|
||||
onTap: widget.onTap,
|
||||
child: SizedBox(
|
||||
height: _kAccountDetailsHeight,
|
||||
width: _kAccountDetailsHeight,
|
||||
child: Center(
|
||||
child: Transform.rotate(
|
||||
angle: _animation.value * math.pi,
|
||||
child: Icon(
|
||||
Icons.arrow_drop_down,
|
||||
color: widget.arrowColor,
|
||||
semanticLabel: widget.isOpen
|
||||
? localizations.hideAccountsLabel
|
||||
: localizations.showAccountsLabel,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (widget.onTap != null) {
|
||||
|
@ -533,15 +533,12 @@ class Border extends BoxBorder {
|
||||
String toString() {
|
||||
if (isUniform)
|
||||
return '$runtimeType.all($top)';
|
||||
final List<String> arguments = <String>[];
|
||||
if (top != BorderSide.none)
|
||||
arguments.add('top: $top');
|
||||
if (right != BorderSide.none)
|
||||
arguments.add('right: $right');
|
||||
if (bottom != BorderSide.none)
|
||||
arguments.add('bottom: $bottom');
|
||||
if (left != BorderSide.none)
|
||||
arguments.add('left: $left');
|
||||
final List<String> arguments = <String>[
|
||||
if (top != BorderSide.none) 'top: $top',
|
||||
if (right != BorderSide.none) 'right: $right',
|
||||
if (bottom != BorderSide.none) 'bottom: $bottom',
|
||||
if (left != BorderSide.none) 'left: $left',
|
||||
];
|
||||
return '$runtimeType(${arguments.join(", ")})';
|
||||
}
|
||||
}
|
||||
@ -838,15 +835,12 @@ class BorderDirectional extends BoxBorder {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> arguments = <String>[];
|
||||
if (top != BorderSide.none)
|
||||
arguments.add('top: $top');
|
||||
if (start != BorderSide.none)
|
||||
arguments.add('start: $start');
|
||||
if (end != BorderSide.none)
|
||||
arguments.add('end: $end');
|
||||
if (bottom != BorderSide.none)
|
||||
arguments.add('bottom: $bottom');
|
||||
final List<String> arguments = <String>[
|
||||
if (top != BorderSide.none) 'top: $top',
|
||||
if (start != BorderSide.none) 'start: $start',
|
||||
if (end != BorderSide.none) 'end: $end',
|
||||
if (bottom != BorderSide.none) 'bottom: $bottom',
|
||||
];
|
||||
return '$runtimeType(${arguments.join(", ")})';
|
||||
}
|
||||
}
|
||||
|
@ -104,15 +104,12 @@ class BoxShadow extends ui.Shadow {
|
||||
return null;
|
||||
a ??= <BoxShadow>[];
|
||||
b ??= <BoxShadow>[];
|
||||
final List<BoxShadow> result = <BoxShadow>[];
|
||||
final int commonLength = math.min(a.length, b.length);
|
||||
for (int i = 0; i < commonLength; i += 1)
|
||||
result.add(BoxShadow.lerp(a[i], b[i], t));
|
||||
for (int i = commonLength; i < a.length; i += 1)
|
||||
result.add(a[i].scale(1.0 - t));
|
||||
for (int i = commonLength; i < b.length; i += 1)
|
||||
result.add(b[i].scale(t));
|
||||
return result;
|
||||
return <BoxShadow>[
|
||||
for (int i = 0; i < commonLength; i += 1) BoxShadow.lerp(a[i], b[i], t),
|
||||
for (int i = commonLength; i < a.length; i += 1) a[i].scale(1.0 - t),
|
||||
for (int i = commonLength; i < b.length; i += 1) b[i].scale(t),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -156,21 +156,22 @@ class DecorationImage {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> properties = <String>[];
|
||||
properties.add('$image');
|
||||
if (colorFilter != null)
|
||||
properties.add('$colorFilter');
|
||||
if (fit != null &&
|
||||
!(fit == BoxFit.fill && centerSlice != null) &&
|
||||
!(fit == BoxFit.scaleDown && centerSlice == null))
|
||||
properties.add('$fit');
|
||||
properties.add('$alignment');
|
||||
if (centerSlice != null)
|
||||
properties.add('centerSlice: $centerSlice');
|
||||
if (repeat != ImageRepeat.noRepeat)
|
||||
properties.add('$repeat');
|
||||
if (matchTextDirection)
|
||||
properties.add('match text direction');
|
||||
final List<String> properties = <String>[
|
||||
'$image',
|
||||
if (colorFilter != null)
|
||||
'$colorFilter',
|
||||
if (fit != null &&
|
||||
!(fit == BoxFit.fill && centerSlice != null) &&
|
||||
!(fit == BoxFit.scaleDown && centerSlice == null))
|
||||
'$fit',
|
||||
'$alignment',
|
||||
if (centerSlice != null)
|
||||
'centerSlice: $centerSlice',
|
||||
if (repeat != ImageRepeat.noRepeat)
|
||||
'$repeat',
|
||||
if (matchTextDirection)
|
||||
'match text direction',
|
||||
];
|
||||
return '$runtimeType(${properties.join(", ")})';
|
||||
}
|
||||
}
|
||||
|
@ -578,10 +578,11 @@ class StrutStyle extends Diagnosticable {
|
||||
super.debugFillProperties(properties);
|
||||
if (debugLabel != null)
|
||||
properties.add(MessageProperty('${prefix}debugLabel', debugLabel));
|
||||
final List<DiagnosticsNode> styles = <DiagnosticsNode>[];
|
||||
styles.add(StringProperty('${prefix}family', fontFamily, defaultValue: null, quoted: false));
|
||||
styles.add(IterableProperty<String>('${prefix}familyFallback', fontFamilyFallback, defaultValue: null));
|
||||
styles.add(DoubleProperty('${prefix}size', fontSize, defaultValue: null));
|
||||
final List<DiagnosticsNode> styles = <DiagnosticsNode>[
|
||||
StringProperty('${prefix}family', fontFamily, defaultValue: null, quoted: false),
|
||||
IterableProperty<String>('${prefix}familyFallback', fontFamilyFallback, defaultValue: null),
|
||||
DoubleProperty('${prefix}size', fontSize, defaultValue: null),
|
||||
];
|
||||
String weightDescription;
|
||||
if (fontWeight != null) {
|
||||
weightDescription = 'w${fontWeight.index + 1}00';
|
||||
|
@ -1202,12 +1202,13 @@ class TextStyle extends Diagnosticable {
|
||||
super.debugFillProperties(properties);
|
||||
if (debugLabel != null)
|
||||
properties.add(MessageProperty('${prefix}debugLabel', debugLabel));
|
||||
final List<DiagnosticsNode> styles = <DiagnosticsNode>[];
|
||||
styles.add(ColorProperty('${prefix}color', color, defaultValue: null));
|
||||
styles.add(ColorProperty('${prefix}backgroundColor', backgroundColor, defaultValue: null));
|
||||
styles.add(StringProperty('${prefix}family', fontFamily, defaultValue: null, quoted: false));
|
||||
styles.add(IterableProperty<String>('${prefix}familyFallback', fontFamilyFallback, defaultValue: null));
|
||||
styles.add(DoubleProperty('${prefix}size', fontSize, defaultValue: null));
|
||||
final List<DiagnosticsNode> styles = <DiagnosticsNode>[
|
||||
ColorProperty('${prefix}color', color, defaultValue: null),
|
||||
ColorProperty('${prefix}backgroundColor', backgroundColor, defaultValue: null),
|
||||
StringProperty('${prefix}family', fontFamily, defaultValue: null, quoted: false),
|
||||
IterableProperty<String>('${prefix}familyFallback', fontFamilyFallback, defaultValue: null),
|
||||
DoubleProperty('${prefix}size', fontSize, defaultValue: null),
|
||||
];
|
||||
String weightDescription;
|
||||
if (fontWeight != null) {
|
||||
weightDescription = '${fontWeight.index + 1}00';
|
||||
|
@ -505,15 +505,12 @@ class BoxConstraints extends Constraints {
|
||||
]);
|
||||
}
|
||||
if (minWidth.isNaN || maxWidth.isNaN || minHeight.isNaN || maxHeight.isNaN) {
|
||||
final List<String> affectedFieldsList = <String>[];
|
||||
if (minWidth.isNaN)
|
||||
affectedFieldsList.add('minWidth');
|
||||
if (maxWidth.isNaN)
|
||||
affectedFieldsList.add('maxWidth');
|
||||
if (minHeight.isNaN)
|
||||
affectedFieldsList.add('minHeight');
|
||||
if (maxHeight.isNaN)
|
||||
affectedFieldsList.add('maxHeight');
|
||||
final List<String> affectedFieldsList = <String>[
|
||||
if (minWidth.isNaN) 'minWidth',
|
||||
if (maxWidth.isNaN) 'maxWidth',
|
||||
if (minHeight.isNaN) 'minHeight',
|
||||
if (maxHeight.isNaN) 'maxHeight',
|
||||
];
|
||||
assert(affectedFieldsList.isNotEmpty);
|
||||
if (affectedFieldsList.length > 1)
|
||||
affectedFieldsList.add('and ${affectedFieldsList.removeLast()}');
|
||||
@ -1711,8 +1708,9 @@ abstract class RenderBox extends RenderObject {
|
||||
(!sizedByParent && debugDoingThisLayout))
|
||||
return true;
|
||||
assert(!debugDoingThisResize);
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[];
|
||||
information.add(ErrorSummary('RenderBox size setter called incorrectly.'));
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[
|
||||
ErrorSummary('RenderBox size setter called incorrectly.'),
|
||||
];
|
||||
if (debugDoingThisLayout) {
|
||||
assert(sizedByParent);
|
||||
information.add(ErrorDescription('It appears that the size setter was called from performLayout().'));
|
||||
|
@ -217,15 +217,12 @@ mixin DebugOverflowIndicatorMixin on RenderObject {
|
||||
));
|
||||
}
|
||||
|
||||
final List<String> overflows = <String>[];
|
||||
if (overflow.left > 0.0)
|
||||
overflows.add('${_formatPixels(overflow.left)} pixels on the left');
|
||||
if (overflow.top > 0.0)
|
||||
overflows.add('${_formatPixels(overflow.top)} pixels on the top');
|
||||
if (overflow.bottom > 0.0)
|
||||
overflows.add('${_formatPixels(overflow.bottom)} pixels on the bottom');
|
||||
if (overflow.right > 0.0)
|
||||
overflows.add('${_formatPixels(overflow.right)} pixels on the right');
|
||||
final List<String> overflows = <String>[
|
||||
if (overflow.left > 0.0) '${_formatPixels(overflow.left)} pixels on the left',
|
||||
if (overflow.top > 0.0) '${_formatPixels(overflow.top)} pixels on the top',
|
||||
if (overflow.bottom > 0.0) '${_formatPixels(overflow.bottom)} pixels on the bottom',
|
||||
if (overflow.right > 0.0) '${_formatPixels(overflow.right)} pixels on the right',
|
||||
];
|
||||
String overflowText = '';
|
||||
assert(overflows.isNotEmpty,
|
||||
"Somehow $runtimeType didn't actually overflow like it thought it did.");
|
||||
|
@ -44,12 +44,11 @@ class TextParentData extends ContainerBoxParentData<RenderBox> {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> values = <String>[];
|
||||
if (offset != null)
|
||||
values.add('offset=$offset');
|
||||
if (scale != null)
|
||||
values.add('scale=$scale');
|
||||
values.add(super.toString());
|
||||
final List<String> values = <String>[
|
||||
if (offset != null) 'offset=$offset',
|
||||
if (scale != null) 'scale=$scale',
|
||||
super.toString(),
|
||||
];
|
||||
return values.join('; ');
|
||||
}
|
||||
}
|
||||
|
@ -3456,15 +3456,12 @@ class RenderSemanticsGestureHandler extends RenderProxyBox {
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
final List<String> gestures = <String>[];
|
||||
if (onTap != null)
|
||||
gestures.add('tap');
|
||||
if (onLongPress != null)
|
||||
gestures.add('long press');
|
||||
if (onHorizontalDragUpdate != null)
|
||||
gestures.add('horizontal scroll');
|
||||
if (onVerticalDragUpdate != null)
|
||||
gestures.add('vertical scroll');
|
||||
final List<String> gestures = <String>[
|
||||
if (onTap != null) 'tap',
|
||||
if (onLongPress != null) 'long press',
|
||||
if (onHorizontalDragUpdate != null) 'horizontal scroll',
|
||||
if (onVerticalDragUpdate != null) 'vertical scroll',
|
||||
];
|
||||
if (gestures.isEmpty)
|
||||
gestures.add('<none>');
|
||||
properties.add(IterableProperty<String>('gestures', gestures));
|
||||
|
@ -953,21 +953,20 @@ class SliverPhysicalParentData extends ParentData {
|
||||
class SliverPhysicalContainerParentData extends SliverPhysicalParentData with ContainerParentDataMixin<RenderSliver> { }
|
||||
|
||||
List<DiagnosticsNode> _debugCompareFloats(String labelA, double valueA, String labelB, double valueB) {
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[];
|
||||
if (valueA.toStringAsFixed(1) != valueB.toStringAsFixed(1)) {
|
||||
information..add(ErrorDescription(
|
||||
'The $labelA is ${valueA.toStringAsFixed(1)}, but '
|
||||
'the $labelB is ${valueB.toStringAsFixed(1)}.'
|
||||
));
|
||||
} else {
|
||||
information
|
||||
..add(ErrorDescription('The $labelA is $valueA, but the $labelB is $valueB.'))
|
||||
..add(ErrorHint(
|
||||
return <DiagnosticsNode>[
|
||||
if (valueA.toStringAsFixed(1) != valueB.toStringAsFixed(1))
|
||||
ErrorDescription(
|
||||
'The $labelA is ${valueA.toStringAsFixed(1)}, but '
|
||||
'the $labelB is ${valueB.toStringAsFixed(1)}.'
|
||||
)
|
||||
else ...<DiagnosticsNode>[
|
||||
ErrorDescription('The $labelA is $valueA, but the $labelB is $valueB.'),
|
||||
ErrorHint(
|
||||
'Maybe you have fallen prey to floating point rounding errors, and should explicitly '
|
||||
'apply the min() or max() functions, or the clamp() method, to the $labelB?'
|
||||
));
|
||||
}
|
||||
return information;
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/// Base class for the render objects that implement scroll effects in viewports.
|
||||
@ -1146,13 +1145,11 @@ abstract class RenderSliver extends RenderObject {
|
||||
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[
|
||||
ErrorSummary('RenderSliver geometry setter called incorrectly.'),
|
||||
violation
|
||||
violation,
|
||||
if (hint != null) hint,
|
||||
contract,
|
||||
describeForError('The RenderSliver in question is'),
|
||||
];
|
||||
if (hint != null)
|
||||
information.add(hint);
|
||||
information.add(contract);
|
||||
information.add(describeForError('The RenderSliver in question is'));
|
||||
|
||||
throw FlutterError.fromParts(information);
|
||||
}());
|
||||
_geometry = value;
|
||||
|
@ -213,19 +213,14 @@ class StackParentData extends ContainerBoxParentData<RenderBox> {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> values = <String>[];
|
||||
if (top != null)
|
||||
values.add('top=${debugFormatDouble(top)}');
|
||||
if (right != null)
|
||||
values.add('right=${debugFormatDouble(right)}');
|
||||
if (bottom != null)
|
||||
values.add('bottom=${debugFormatDouble(bottom)}');
|
||||
if (left != null)
|
||||
values.add('left=${debugFormatDouble(left)}');
|
||||
if (width != null)
|
||||
values.add('width=${debugFormatDouble(width)}');
|
||||
if (height != null)
|
||||
values.add('height=${debugFormatDouble(height)}');
|
||||
final List<String> values = <String>[
|
||||
if (top != null) 'top=${debugFormatDouble(top)}',
|
||||
if (right != null) 'right=${debugFormatDouble(right)}',
|
||||
if (bottom != null) 'bottom=${debugFormatDouble(bottom)}',
|
||||
if (left != null) 'left=${debugFormatDouble(left)}',
|
||||
if (width != null) 'width=${debugFormatDouble(width)}',
|
||||
if (height != null) 'height=${debugFormatDouble(height)}',
|
||||
];
|
||||
if (values.isEmpty)
|
||||
values.add('not positioned');
|
||||
values.add(super.toString());
|
||||
|
@ -363,22 +363,22 @@ class SemanticsData extends Diagnosticable {
|
||||
properties.add(TransformProperty('transform', transform, showName: false, defaultValue: null));
|
||||
properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0));
|
||||
properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0));
|
||||
final List<String> actionSummary = <String>[];
|
||||
for (SemanticsAction action in SemanticsAction.values.values) {
|
||||
if ((actions & action.index) != 0)
|
||||
actionSummary.add(describeEnum(action));
|
||||
}
|
||||
final List<String> actionSummary = <String>[
|
||||
for (SemanticsAction action in SemanticsAction.values.values)
|
||||
if ((actions & action.index) != 0)
|
||||
describeEnum(action),
|
||||
];
|
||||
final List<String> customSemanticsActionSummary = customSemanticsActionIds
|
||||
.map<String>((int actionId) => CustomSemanticsAction.getAction(actionId).label)
|
||||
.toList();
|
||||
properties.add(IterableProperty<String>('actions', actionSummary, ifEmpty: null));
|
||||
properties.add(IterableProperty<String>('customActions', customSemanticsActionSummary, ifEmpty: null));
|
||||
|
||||
final List<String> flagSummary = <String>[];
|
||||
for (SemanticsFlag flag in SemanticsFlag.values.values) {
|
||||
if ((flags & flag.index) != 0)
|
||||
flagSummary.add(describeEnum(flag));
|
||||
}
|
||||
final List<String> flagSummary = <String>[
|
||||
for (SemanticsFlag flag in SemanticsFlag.values.values)
|
||||
if ((flags & flag.index) != 0)
|
||||
describeEnum(flag),
|
||||
];
|
||||
properties.add(IterableProperty<String>('flags', flagSummary, ifEmpty: null));
|
||||
properties.add(StringProperty('label', label, defaultValue: ''));
|
||||
properties.add(StringProperty('value', value, defaultValue: ''));
|
||||
|
@ -206,12 +206,9 @@ class SystemUiOverlayStyle {
|
||||
}
|
||||
}
|
||||
|
||||
List<String> _stringify(List<dynamic> list) {
|
||||
final List<String> result = <String>[];
|
||||
for (dynamic item in list)
|
||||
result.add(item.toString());
|
||||
return result;
|
||||
}
|
||||
List<String> _stringify(List<dynamic> list) => <String>[
|
||||
for (dynamic item in list) item.toString(),
|
||||
];
|
||||
|
||||
/// Controls specific aspects of the operating system's graphical interface and
|
||||
/// how it interacts with the application.
|
||||
|
@ -276,11 +276,11 @@ class AnimatedSwitcher extends StatefulWidget {
|
||||
///
|
||||
/// This is an [AnimatedSwitcherLayoutBuilder] function.
|
||||
static Widget defaultLayoutBuilder(Widget currentChild, List<Widget> previousChildren) {
|
||||
List<Widget> children = previousChildren;
|
||||
if (currentChild != null)
|
||||
children = children.toList()..add(currentChild);
|
||||
return Stack(
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
...previousChildren,
|
||||
if (currentChild != null) currentChild,
|
||||
],
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
}
|
||||
|
@ -5714,17 +5714,13 @@ class _PointerListener extends SingleChildRenderObjectWidget {
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
final List<String> listeners = <String>[];
|
||||
if (onPointerDown != null)
|
||||
listeners.add('down');
|
||||
if (onPointerMove != null)
|
||||
listeners.add('move');
|
||||
if (onPointerUp != null)
|
||||
listeners.add('up');
|
||||
if (onPointerCancel != null)
|
||||
listeners.add('cancel');
|
||||
if (onPointerSignal != null)
|
||||
listeners.add('signal');
|
||||
final List<String> listeners = <String>[
|
||||
if (onPointerDown != null) 'down',
|
||||
if (onPointerMove != null) 'move',
|
||||
if (onPointerUp != null) 'up',
|
||||
if (onPointerCancel != null) 'cancel',
|
||||
if (onPointerSignal != null) 'signal',
|
||||
];
|
||||
properties.add(IterableProperty<String>('listeners', listeners, ifEmpty: '<none>'));
|
||||
properties.add(EnumProperty<HitTestBehavior>('behavior', behavior));
|
||||
}
|
||||
|
@ -549,22 +549,19 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
|
||||
);
|
||||
|
||||
if (background != null) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (!_moveAnimation.isDismissed) {
|
||||
children.add(Positioned.fill(
|
||||
child: ClipRect(
|
||||
clipper: _DismissibleClipper(
|
||||
axis: _directionIsXAxis ? Axis.horizontal : Axis.vertical,
|
||||
moveAnimation: _moveAnimation,
|
||||
content = Stack(children: <Widget>[
|
||||
if (!_moveAnimation.isDismissed)
|
||||
Positioned.fill(
|
||||
child: ClipRect(
|
||||
clipper: _DismissibleClipper(
|
||||
axis: _directionIsXAxis ? Axis.horizontal : Axis.vertical,
|
||||
moveAnimation: _moveAnimation,
|
||||
),
|
||||
child: background,
|
||||
),
|
||||
child: background,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
children.add(content);
|
||||
content = Stack(children: children);
|
||||
content,
|
||||
]);
|
||||
}
|
||||
// We are not resizing but we may be being dragging in widget.direction.
|
||||
return GestureDetector(
|
||||
|
@ -657,10 +657,9 @@ class ReadingOrderTraversalPolicy extends FocusTraversalPolicy with DirectionalF
|
||||
return topmost;
|
||||
}
|
||||
|
||||
final List<_SortData> data = <_SortData>[];
|
||||
for (FocusNode node in nodes) {
|
||||
data.add(_SortData(node));
|
||||
}
|
||||
final List<_SortData> data = <_SortData>[
|
||||
for (FocusNode node in nodes) _SortData(node),
|
||||
];
|
||||
|
||||
// Pick the initial widget as the one that is leftmost in the band of the
|
||||
// topmost, or the topmost, if there are no others in its band.
|
||||
|
@ -263,15 +263,14 @@ class FixedExtentScrollController extends ScrollController {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Future<void>> futures = <Future<void>>[];
|
||||
for (_FixedExtentScrollPosition position in positions) {
|
||||
futures.add(position.animateTo(
|
||||
itemIndex * position.itemExtent,
|
||||
duration: duration,
|
||||
curve: curve,
|
||||
));
|
||||
}
|
||||
await Future.wait<void>(futures);
|
||||
await Future.wait<void>(<Future<void>>[
|
||||
for (_FixedExtentScrollPosition position in positions)
|
||||
position.animateTo(
|
||||
itemIndex * position.itemExtent,
|
||||
duration: duration,
|
||||
curve: curve,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Changes which item index is centered in the controlled scroll view.
|
||||
|
@ -61,17 +61,6 @@ class NavigationToolbar extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasDirectionality(context));
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
if (leading != null)
|
||||
children.add(LayoutId(id: _ToolbarSlot.leading, child: leading));
|
||||
|
||||
if (middle != null)
|
||||
children.add(LayoutId(id: _ToolbarSlot.middle, child: middle));
|
||||
|
||||
if (trailing != null)
|
||||
children.add(LayoutId(id: _ToolbarSlot.trailing, child: trailing));
|
||||
|
||||
final TextDirection textDirection = Directionality.of(context);
|
||||
return CustomMultiChildLayout(
|
||||
delegate: _ToolbarLayout(
|
||||
@ -79,7 +68,11 @@ class NavigationToolbar extends StatelessWidget {
|
||||
middleSpacing: middleSpacing,
|
||||
textDirection: textDirection,
|
||||
),
|
||||
children: children,
|
||||
children: <Widget>[
|
||||
if (leading != null) LayoutId(id: _ToolbarSlot.leading, child: leading),
|
||||
if (middle != null) LayoutId(id: _ToolbarSlot.middle, child: middle),
|
||||
if (trailing != null) LayoutId(id: _ToolbarSlot.trailing, child: trailing),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -660,10 +660,9 @@ class _RenderTheatre extends RenderBox
|
||||
|
||||
@override
|
||||
List<DiagnosticsNode> debugDescribeChildren() {
|
||||
final List<DiagnosticsNode> children = <DiagnosticsNode>[];
|
||||
|
||||
if (child != null)
|
||||
children.add(child.toDiagnosticsNode(name: 'onstage'));
|
||||
final List<DiagnosticsNode> children = <DiagnosticsNode>[
|
||||
if (child != null) child.toDiagnosticsNode(name: 'onstage'),
|
||||
];
|
||||
|
||||
if (firstChild != null) {
|
||||
RenderBox child = firstChild;
|
||||
|
@ -589,11 +589,10 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final List<Listenable> animations = <Listenable>[];
|
||||
if (widget.route.animation != null)
|
||||
animations.add(widget.route.animation);
|
||||
if (widget.route.secondaryAnimation != null)
|
||||
animations.add(widget.route.secondaryAnimation);
|
||||
final List<Listenable> animations = <Listenable>[
|
||||
if (widget.route.animation != null) widget.route.animation,
|
||||
if (widget.route.secondaryAnimation != null) widget.route.secondaryAnimation,
|
||||
];
|
||||
_listenable = Listenable.merge(animations);
|
||||
if (widget.route.isCurrent) {
|
||||
widget.route.navigator.focusScopeNode.setFirstFocus(focusScopeNode);
|
||||
|
@ -143,11 +143,10 @@ class SliverPersistentHeader extends StatelessWidget {
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(DiagnosticsProperty<SliverPersistentHeaderDelegate>('delegate', delegate));
|
||||
final List<String> flags = <String>[];
|
||||
if (pinned)
|
||||
flags.add('pinned');
|
||||
if (floating)
|
||||
flags.add('floating');
|
||||
final List<String> flags = <String>[
|
||||
if (pinned) 'pinned',
|
||||
if (floating) 'floating',
|
||||
];
|
||||
if (flags.isEmpty)
|
||||
flags.add('normal');
|
||||
properties.add(IterableProperty<String>('mode', flags));
|
||||
|
@ -2267,30 +2267,29 @@ class _WidgetInspectorState extends State<WidgetInspector>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
children.add(GestureDetector(
|
||||
onTap: _handleTap,
|
||||
onPanDown: _handlePanDown,
|
||||
onPanEnd: _handlePanEnd,
|
||||
onPanUpdate: _handlePanUpdate,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
excludeFromSemantics: true,
|
||||
child: IgnorePointer(
|
||||
ignoring: isSelectMode,
|
||||
key: _ignorePointerKey,
|
||||
ignoringSemantics: false,
|
||||
child: widget.child,
|
||||
return Stack(children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: _handleTap,
|
||||
onPanDown: _handlePanDown,
|
||||
onPanEnd: _handlePanEnd,
|
||||
onPanUpdate: _handlePanUpdate,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
excludeFromSemantics: true,
|
||||
child: IgnorePointer(
|
||||
ignoring: isSelectMode,
|
||||
key: _ignorePointerKey,
|
||||
ignoringSemantics: false,
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
));
|
||||
if (!isSelectMode && widget.selectButtonBuilder != null) {
|
||||
children.add(Positioned(
|
||||
left: _kInspectButtonMargin,
|
||||
bottom: _kInspectButtonMargin,
|
||||
child: widget.selectButtonBuilder(context, _handleEnableSelect),
|
||||
));
|
||||
}
|
||||
children.add(_InspectorOverlay(selection: selection));
|
||||
return Stack(children: children);
|
||||
if (!isSelectMode && widget.selectButtonBuilder != null)
|
||||
Positioned(
|
||||
left: _kInspectButtonMargin,
|
||||
bottom: _kInspectButtonMargin,
|
||||
child: widget.selectButtonBuilder(context, _handleEnableSelect),
|
||||
),
|
||||
_InspectorOverlay(selection: selection),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,19 +105,19 @@ void main() {
|
||||
});
|
||||
|
||||
List<double> estimateBounds(Curve curve) {
|
||||
final List<double> values = <double>[];
|
||||
|
||||
values.add(curve.transform(0.0));
|
||||
values.add(curve.transform(0.1));
|
||||
values.add(curve.transform(0.2));
|
||||
values.add(curve.transform(0.3));
|
||||
values.add(curve.transform(0.4));
|
||||
values.add(curve.transform(0.5));
|
||||
values.add(curve.transform(0.6));
|
||||
values.add(curve.transform(0.7));
|
||||
values.add(curve.transform(0.8));
|
||||
values.add(curve.transform(0.9));
|
||||
values.add(curve.transform(1.0));
|
||||
final List<double> values = <double>[
|
||||
curve.transform(0.0),
|
||||
curve.transform(0.1),
|
||||
curve.transform(0.2),
|
||||
curve.transform(0.3),
|
||||
curve.transform(0.4),
|
||||
curve.transform(0.5),
|
||||
curve.transform(0.6),
|
||||
curve.transform(0.7),
|
||||
curve.transform(0.8),
|
||||
curve.transform(0.9),
|
||||
curve.transform(1.0),
|
||||
];
|
||||
|
||||
return <double>[
|
||||
values.reduce(math.min),
|
||||
|
@ -246,16 +246,13 @@ class TestTree extends Object with DiagnosticableTreeMixin {
|
||||
final DiagnosticsTreeStyle style;
|
||||
|
||||
@override
|
||||
List<DiagnosticsNode> debugDescribeChildren() {
|
||||
final List<DiagnosticsNode> children = <DiagnosticsNode>[];
|
||||
for (TestTree child in this.children) {
|
||||
children.add(child.toDiagnosticsNode(
|
||||
List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[
|
||||
for (TestTree child in children)
|
||||
child.toDiagnosticsNode(
|
||||
name: 'child ${child.name}',
|
||||
style: child.style,
|
||||
));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
|
@ -22,16 +22,13 @@ class TestTree extends Object with DiagnosticableTreeMixin {
|
||||
final DiagnosticsTreeStyle style;
|
||||
|
||||
@override
|
||||
List<DiagnosticsNode> debugDescribeChildren() {
|
||||
final List<DiagnosticsNode> children = <DiagnosticsNode>[];
|
||||
for (TestTree child in this.children) {
|
||||
children.add(child.toDiagnosticsNode(
|
||||
List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[
|
||||
for (TestTree child in children)
|
||||
child.toDiagnosticsNode(
|
||||
name: 'child ${child.name}',
|
||||
style: child.style,
|
||||
));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
|
@ -371,9 +371,9 @@ void main() {
|
||||
|
||||
testWidgets('Dropdown screen edges', (WidgetTester tester) async {
|
||||
int value = 4;
|
||||
final List<DropdownMenuItem<int>> items = <DropdownMenuItem<int>>[];
|
||||
for (int i = 0; i < 20; ++i)
|
||||
items.add(DropdownMenuItem<int>(value: i, child: Text('$i')));
|
||||
final List<DropdownMenuItem<int>> items = <DropdownMenuItem<int>>[
|
||||
for (int i = 0; i < 20; ++i) DropdownMenuItem<int>(value: i, child: Text('$i')),
|
||||
];
|
||||
|
||||
void handleChanged(int newValue) {
|
||||
value = newValue;
|
||||
|
@ -237,11 +237,11 @@ void main() {
|
||||
});
|
||||
|
||||
test('Notifies listeners of chunk events', () async {
|
||||
final List<Uint8List> chunks = <Uint8List>[];
|
||||
const int chunkSize = 8;
|
||||
for (int offset = 0; offset < kTransparentImage.length; offset += chunkSize) {
|
||||
chunks.add(Uint8List.fromList(kTransparentImage.skip(offset).take(chunkSize).toList()));
|
||||
}
|
||||
final List<Uint8List> chunks = <Uint8List>[
|
||||
for (int offset = 0; offset < kTransparentImage.length; offset += chunkSize)
|
||||
Uint8List.fromList(kTransparentImage.skip(offset).take(chunkSize).toList()),
|
||||
];
|
||||
final Completer<void> imageAvailable = Completer<void>();
|
||||
final MockHttpClientRequest request = MockHttpClientRequest();
|
||||
final MockHttpClientResponse response = MockHttpClientResponse();
|
||||
|
@ -127,10 +127,11 @@ void main() {
|
||||
// The list is currently in the wrong order (so selection boxes will paint in the wrong order).
|
||||
);
|
||||
|
||||
final List<List<TextBox>> list = <List<TextBox>>[];
|
||||
textSpan = painter.text;
|
||||
for (int index = 0; index < textSpan.text.length; index += 1)
|
||||
list.add(painter.getBoxesForSelection(TextSelection(baseOffset: index, extentOffset: index + 1)));
|
||||
final List<List<TextBox>> list = <List<TextBox>>[
|
||||
for (int index = 0; index < textSpan.text.length; index += 1)
|
||||
painter.getBoxesForSelection(TextSelection(baseOffset: index, extentOffset: index + 1)),
|
||||
];
|
||||
expect(list, const <List<TextBox>>[
|
||||
<TextBox>[], // U+202E, non-printing Unicode bidi formatting character
|
||||
<TextBox>[TextBox.fromLTRBD(230.0, 0.0, 240.0, 10.0, TextDirection.rtl)],
|
||||
@ -390,10 +391,11 @@ void main() {
|
||||
skip: skipExpectsWithKnownBugs, // horizontal offsets are one pixel off in places; vertical offsets are good
|
||||
);
|
||||
|
||||
final List<List<TextBox>> list = <List<TextBox>>[];
|
||||
for (int index = 0; index < 5+4+5; index += 1)
|
||||
list.add(painter.getBoxesForSelection(TextSelection(baseOffset: index, extentOffset: index + 1)));
|
||||
print(list);
|
||||
final List<List<TextBox>> list = <List<TextBox>>[
|
||||
for (int index = 0; index < 5+4+5; index += 1)
|
||||
painter.getBoxesForSelection(TextSelection(baseOffset: index, extentOffset: index + 1)),
|
||||
];
|
||||
|
||||
expect(list, const <List<TextBox>>[
|
||||
<TextBox>[TextBox.fromLTRBD(0.0, 8.0, 10.0, 18.0, TextDirection.ltr)],
|
||||
<TextBox>[TextBox.fromLTRBD(10.0, 8.0, 20.0, 18.0, TextDirection.ltr)],
|
||||
|
@ -444,15 +444,14 @@ class _PathMatcher extends Matcher {
|
||||
return false;
|
||||
}
|
||||
final Path path = object;
|
||||
final List<String> errors = <String>[];
|
||||
for (Offset offset in includes) {
|
||||
if (!path.contains(offset))
|
||||
errors.add('Offset $offset should be inside the path, but is not.');
|
||||
}
|
||||
for (Offset offset in excludes) {
|
||||
if (path.contains(offset))
|
||||
errors.add('Offset $offset should be outside the path, but is not.');
|
||||
}
|
||||
final List<String> errors = <String>[
|
||||
for (Offset offset in includes)
|
||||
if (!path.contains(offset))
|
||||
'Offset $offset should be inside the path, but is not.',
|
||||
for (Offset offset in excludes)
|
||||
if (path.contains(offset))
|
||||
'Offset $offset should be outside the path, but is not.',
|
||||
];
|
||||
if (errors.isEmpty)
|
||||
return true;
|
||||
matchState[this] = 'Not all the given points were inside or outside the path as expected:\n ${errors.join("\n ")}';
|
||||
@ -1458,9 +1457,10 @@ class _FunctionPaintPredicate extends _PaintPredicate {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final List<String> adjectives = <String>[];
|
||||
for (int index = 0; index < arguments.length; index += 1)
|
||||
adjectives.add(arguments[index] != null ? _valueName(arguments[index]) : '...');
|
||||
final List<String> adjectives = <String>[
|
||||
for (int index = 0; index < arguments.length; index += 1)
|
||||
arguments[index] != null ? _valueName(arguments[index]) : '...',
|
||||
];
|
||||
return '${_symbolName(symbol)}(${adjectives.join(", ")})';
|
||||
}
|
||||
}
|
||||
|
@ -338,10 +338,11 @@ void main() {
|
||||
);
|
||||
// Fake the render boxes that correspond to the WidgetSpans. We use
|
||||
// RenderParagraph to reduce dependencies this test has.
|
||||
final List<RenderBox> renderBoxes = <RenderBox>[];
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
final List<RenderBox> renderBoxes = <RenderBox>[
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
];
|
||||
|
||||
final RenderParagraph paragraph = RenderParagraph(
|
||||
text,
|
||||
@ -380,14 +381,15 @@ void main() {
|
||||
);
|
||||
// Fake the render boxes that correspond to the WidgetSpans. We use
|
||||
// RenderParagraph to reduce dependencies this test has.
|
||||
final List<RenderBox> renderBoxes = <RenderBox>[];
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
renderBoxes.add(RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr));
|
||||
final List<RenderBox> renderBoxes = <RenderBox>[
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
|
||||
];
|
||||
|
||||
final RenderParagraph paragraph = RenderParagraph(
|
||||
text,
|
||||
|
@ -263,10 +263,9 @@ void main() {
|
||||
];
|
||||
final List<int> expectedResults = <int>[0, -1, 1, 0];
|
||||
assert(tests.length == expectedResults.length);
|
||||
final List<int> results = <int>[];
|
||||
for (List<SemanticsSortKey> tuple in tests) {
|
||||
results.add(tuple[0].compareTo(tuple[1]));
|
||||
}
|
||||
final List<int> results = <int>[
|
||||
for (List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
||||
];
|
||||
expect(results, orderedEquals(expectedResults));
|
||||
});
|
||||
|
||||
@ -279,10 +278,9 @@ void main() {
|
||||
];
|
||||
final List<int> expectedResults = <int>[0, -1, 1, 0];
|
||||
assert(tests.length == expectedResults.length);
|
||||
final List<int> results = <int>[];
|
||||
for (List<SemanticsSortKey> tuple in tests) {
|
||||
results.add(tuple[0].compareTo(tuple[1]));
|
||||
}
|
||||
final List<int> results = <int>[
|
||||
for (List<SemanticsSortKey> tuple in tests) tuple[0].compareTo(tuple[1]),
|
||||
];
|
||||
expect(results, orderedEquals(expectedResults));
|
||||
});
|
||||
|
||||
|
@ -708,21 +708,17 @@ class _DiffTester {
|
||||
final SemanticsTester semanticsTester = SemanticsTester(tester);
|
||||
|
||||
TestSemantics createExpectations(List<String> labels) {
|
||||
final List<TestSemantics> children = <TestSemantics>[];
|
||||
for (String label in labels) {
|
||||
children.add(
|
||||
TestSemantics(
|
||||
rect: const Rect.fromLTRB(1.0, 1.0, 2.0, 2.0),
|
||||
label: label,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return TestSemantics.root(
|
||||
children: <TestSemantics>[
|
||||
TestSemantics.rootChild(
|
||||
rect: TestSemantics.fullScreen,
|
||||
children: children,
|
||||
children: <TestSemantics>[
|
||||
for (String label in labels)
|
||||
TestSemantics(
|
||||
rect: const Rect.fromLTRB(1.0, 1.0, 2.0, 2.0),
|
||||
label: label,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -29,17 +29,17 @@ class OrderSwitcherState extends State<OrderSwitcher> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
if (_aFirst) {
|
||||
children.add(KeyedSubtree(child: widget.a));
|
||||
children.add(widget.b);
|
||||
} else {
|
||||
children.add(KeyedSubtree(child: widget.b));
|
||||
children.add(widget.a);
|
||||
}
|
||||
return Stack(
|
||||
textDirection: TextDirection.ltr,
|
||||
children: children,
|
||||
children: _aFirst
|
||||
? <Widget>[
|
||||
KeyedSubtree(child: widget.a),
|
||||
widget.b,
|
||||
]
|
||||
: <Widget>[
|
||||
KeyedSubtree(child: widget.b),
|
||||
widget.a
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,15 +8,12 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Does not animate if already at target position', (WidgetTester tester) async {
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
textWidgets.add(Text('$i', textDirection: TextDirection.ltr));
|
||||
final ScrollController controller = ScrollController();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(
|
||||
children: textWidgets,
|
||||
children: List<Widget>.generate(80, (int i) => Text('$i', textDirection: TextDirection.ltr)),
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
@ -31,15 +28,12 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Does not animate if already at target position within tolerance', (WidgetTester tester) async {
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
textWidgets.add(Text('$i', textDirection: TextDirection.ltr));
|
||||
final ScrollController controller = ScrollController();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(
|
||||
children: textWidgets,
|
||||
children: List<Widget>.generate(80, (int i) => Text('$i', textDirection: TextDirection.ltr)),
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
@ -57,15 +51,12 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Animates if going to a position outside of tolerance', (WidgetTester tester) async {
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
textWidgets.add(Text('$i', textDirection: TextDirection.ltr));
|
||||
final ScrollController controller = ScrollController();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(
|
||||
children: textWidgets,
|
||||
children: List<Widget>.generate(80, (int i) => Text('$i', textDirection: TextDirection.ltr)),
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
|
@ -11,14 +11,11 @@ import 'test_widgets.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('simultaneously dispose a widget and end the scroll animation', (WidgetTester tester) async {
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 250; i++)
|
||||
textWidgets.add(Text('$i'));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: FlipWidget(
|
||||
left: ListView(children: textWidgets),
|
||||
left: ListView(children: List<Widget>.generate(250, (int i) => Text('$i'))),
|
||||
right: Container(),
|
||||
),
|
||||
),
|
||||
|
@ -59,14 +59,16 @@ void main() {
|
||||
|
||||
testWidgets('fling and tap to stop', (WidgetTester tester) async {
|
||||
final List<String> log = <String>[];
|
||||
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 250; i += 1)
|
||||
textWidgets.add(GestureDetector(onTap: () { log.add('tap $i'); }, child: Text('$i', style: testFont)));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(children: textWidgets, dragStartBehavior: DragStartBehavior.down),
|
||||
child: ListView(
|
||||
dragStartBehavior: DragStartBehavior.down,
|
||||
children: List<Widget>.generate(250, (int i) => GestureDetector(
|
||||
onTap: () { log.add('tap $i'); },
|
||||
child: Text('$i', style: testFont),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -87,14 +89,16 @@ void main() {
|
||||
|
||||
testWidgets('fling and wait and tap', (WidgetTester tester) async {
|
||||
final List<String> log = <String>[];
|
||||
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 250; i += 1)
|
||||
textWidgets.add(GestureDetector(onTap: () { log.add('tap $i'); }, child: Text('$i', style: testFont)));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(children: textWidgets, dragStartBehavior: DragStartBehavior.down),
|
||||
child: ListView(
|
||||
dragStartBehavior: DragStartBehavior.down,
|
||||
children: List<Widget>.generate(250, (int i) => GestureDetector(
|
||||
onTap: () { log.add('tap $i'); },
|
||||
child: Text('$i', style: testFont),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -21,14 +21,10 @@ void main() {
|
||||
|
||||
testWidgets('scrollable exposes the correct semantic actions', (WidgetTester tester) async {
|
||||
semantics = SemanticsTester(tester);
|
||||
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
textWidgets.add(Text('$i'));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(children: textWidgets),
|
||||
child: ListView(children: List<Widget>.generate(80, (int i) => Text('$i'))),
|
||||
),
|
||||
);
|
||||
|
||||
@ -54,12 +50,12 @@ void main() {
|
||||
|
||||
const double kItemHeight = 40.0;
|
||||
|
||||
final List<Widget> containers = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
containers.add(MergeSemantics(child: Container(
|
||||
final List<Widget> containers = List<Widget>.generate(80, (int i) => MergeSemantics(
|
||||
child: Container(
|
||||
height: kItemHeight,
|
||||
child: Text('container $i', textDirection: TextDirection.ltr),
|
||||
)));
|
||||
),
|
||||
));
|
||||
|
||||
final ScrollController scrollController = ScrollController(
|
||||
initialScrollOffset: kItemHeight / 2,
|
||||
@ -93,12 +89,12 @@ void main() {
|
||||
const double kItemHeight = 100.0;
|
||||
const double kExpandedAppBarHeight = 56.0;
|
||||
|
||||
final List<Widget> containers = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
containers.add(MergeSemantics(child: Container(
|
||||
final List<Widget> containers = List<Widget>.generate(80, (int i) => MergeSemantics(
|
||||
child: Container(
|
||||
height: kItemHeight,
|
||||
child: Text('container $i'),
|
||||
)));
|
||||
),
|
||||
));
|
||||
|
||||
final ScrollController scrollController = ScrollController(
|
||||
initialScrollOffset: kItemHeight / 2,
|
||||
@ -219,12 +215,9 @@ void main() {
|
||||
testWidgets('correct scrollProgress', (WidgetTester tester) async {
|
||||
semantics = SemanticsTester(tester);
|
||||
|
||||
final List<Widget> textWidgets = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
textWidgets.add(Text('$i'));
|
||||
await tester.pumpWidget(Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: ListView(children: textWidgets),
|
||||
child: ListView(children: List<Widget>.generate(80, (int i) => Text('$i'))),
|
||||
));
|
||||
|
||||
expect(semantics, includesNodeWith(
|
||||
@ -315,12 +308,10 @@ void main() {
|
||||
testWidgets('Semantics tree is populated mid-scroll', (WidgetTester tester) async {
|
||||
semantics = SemanticsTester(tester);
|
||||
|
||||
final List<Widget> children = <Widget>[];
|
||||
for (int i = 0; i < 80; i++)
|
||||
children.add(Container(
|
||||
child: Text('Item $i'),
|
||||
height: 40.0,
|
||||
));
|
||||
final List<Widget> children = List<Widget>.generate(80, (int i) => Container(
|
||||
child: Text('Item $i'),
|
||||
height: 40.0,
|
||||
));
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
|
@ -751,25 +751,17 @@ class _IncludesNodeWith extends Matcher {
|
||||
}
|
||||
|
||||
String get _configAsString {
|
||||
final List<String> strings = <String>[];
|
||||
if (label != null)
|
||||
strings.add('label "$label"');
|
||||
if (value != null)
|
||||
strings.add('value "$value"');
|
||||
if (hint != null)
|
||||
strings.add('hint "$hint"');
|
||||
if (textDirection != null)
|
||||
strings.add(' (${describeEnum(textDirection)})');
|
||||
if (actions != null)
|
||||
strings.add('actions "${actions.join(', ')}"');
|
||||
if (flags != null)
|
||||
strings.add('flags "${flags.join(', ')}"');
|
||||
if (scrollPosition != null)
|
||||
strings.add('scrollPosition "$scrollPosition"');
|
||||
if (scrollExtentMax != null)
|
||||
strings.add('scrollExtentMax "$scrollExtentMax"');
|
||||
if (scrollExtentMin != null)
|
||||
strings.add('scrollExtentMin "$scrollExtentMin"');
|
||||
final List<String> strings = <String>[
|
||||
if (label != null) 'label "$label"',
|
||||
if (value != null) 'value "$value"',
|
||||
if (hint != null) 'hint "$hint"',
|
||||
if (textDirection != null) ' (${describeEnum(textDirection)})',
|
||||
if (actions != null) 'actions "${actions.join(', ')}"',
|
||||
if (flags != null) 'flags "${flags.join(', ')}"',
|
||||
if (scrollPosition != null) 'scrollPosition "$scrollPosition"',
|
||||
if (scrollExtentMax != null) 'scrollExtentMax "$scrollExtentMax"',
|
||||
if (scrollExtentMin != null) 'scrollExtentMin "$scrollExtentMin"',
|
||||
];
|
||||
return strings.join(', ');
|
||||
}
|
||||
}
|
||||
|
@ -1123,12 +1123,11 @@ void _unhandledJsonRpcError(dynamic error, dynamic stack) {
|
||||
|
||||
String _getWebSocketUrl(String url) {
|
||||
Uri uri = Uri.parse(url);
|
||||
final List<String> pathSegments = <String>[];
|
||||
// If there's an authentication code (default), we need to add it to our path.
|
||||
if (uri.pathSegments.isNotEmpty) {
|
||||
pathSegments.add(uri.pathSegments.first);
|
||||
}
|
||||
pathSegments.add('ws');
|
||||
final List<String> pathSegments = <String>[
|
||||
// If there's an authentication code (default), we need to add it to our path.
|
||||
if (uri.pathSegments.isNotEmpty) uri.pathSegments.first,
|
||||
'ws',
|
||||
];
|
||||
if (uri.scheme == 'http')
|
||||
uri = uri.replace(scheme: 'ws', pathSegments: pathSegments);
|
||||
return uri.toString();
|
||||
|
@ -5,7 +5,7 @@ author: Flutter Authors <flutter-dev@googlegroups.com>
|
||||
|
||||
environment:
|
||||
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
file: 5.0.10
|
||||
|
@ -482,93 +482,53 @@ Matcher matchesSemantics({
|
||||
List<CustomSemanticsAction> customActions,
|
||||
List<Matcher> children,
|
||||
}) {
|
||||
final List<SemanticsFlag> flags = <SemanticsFlag>[];
|
||||
if (hasCheckedState)
|
||||
flags.add(SemanticsFlag.hasCheckedState);
|
||||
if (isChecked)
|
||||
flags.add(SemanticsFlag.isChecked);
|
||||
if (isSelected)
|
||||
flags.add(SemanticsFlag.isSelected);
|
||||
if (isButton)
|
||||
flags.add(SemanticsFlag.isButton);
|
||||
if (isTextField)
|
||||
flags.add(SemanticsFlag.isTextField);
|
||||
if (isReadOnly)
|
||||
flags.add(SemanticsFlag.isReadOnly);
|
||||
if (isFocused)
|
||||
flags.add(SemanticsFlag.isFocused);
|
||||
if (hasEnabledState)
|
||||
flags.add(SemanticsFlag.hasEnabledState);
|
||||
if (isEnabled)
|
||||
flags.add(SemanticsFlag.isEnabled);
|
||||
if (isInMutuallyExclusiveGroup)
|
||||
flags.add(SemanticsFlag.isInMutuallyExclusiveGroup);
|
||||
if (isHeader)
|
||||
flags.add(SemanticsFlag.isHeader);
|
||||
if (isObscured)
|
||||
flags.add(SemanticsFlag.isObscured);
|
||||
if (isMultiline)
|
||||
flags.add(SemanticsFlag.isMultiline);
|
||||
if (namesRoute)
|
||||
flags.add(SemanticsFlag.namesRoute);
|
||||
if (scopesRoute)
|
||||
flags.add(SemanticsFlag.scopesRoute);
|
||||
if (isHidden)
|
||||
flags.add(SemanticsFlag.isHidden);
|
||||
if (isImage)
|
||||
flags.add(SemanticsFlag.isImage);
|
||||
if (isLiveRegion)
|
||||
flags.add(SemanticsFlag.isLiveRegion);
|
||||
if (hasToggledState)
|
||||
flags.add(SemanticsFlag.hasToggledState);
|
||||
if (isToggled)
|
||||
flags.add(SemanticsFlag.isToggled);
|
||||
if (hasImplicitScrolling)
|
||||
flags.add(SemanticsFlag.hasImplicitScrolling);
|
||||
final List<SemanticsFlag> flags = <SemanticsFlag>[
|
||||
if (hasCheckedState) SemanticsFlag.hasCheckedState,
|
||||
if (isChecked) SemanticsFlag.isChecked,
|
||||
if (isSelected) SemanticsFlag.isSelected,
|
||||
if (isButton) SemanticsFlag.isButton,
|
||||
if (isTextField) SemanticsFlag.isTextField,
|
||||
if (isReadOnly) SemanticsFlag.isReadOnly,
|
||||
if (isFocused) SemanticsFlag.isFocused,
|
||||
if (hasEnabledState) SemanticsFlag.hasEnabledState,
|
||||
if (isEnabled) SemanticsFlag.isEnabled,
|
||||
if (isInMutuallyExclusiveGroup) SemanticsFlag.isInMutuallyExclusiveGroup,
|
||||
if (isHeader) SemanticsFlag.isHeader,
|
||||
if (isObscured) SemanticsFlag.isObscured,
|
||||
if (isMultiline) SemanticsFlag.isMultiline,
|
||||
if (namesRoute) SemanticsFlag.namesRoute,
|
||||
if (scopesRoute) SemanticsFlag.scopesRoute,
|
||||
if (isHidden) SemanticsFlag.isHidden,
|
||||
if (isImage) SemanticsFlag.isImage,
|
||||
if (isLiveRegion) SemanticsFlag.isLiveRegion,
|
||||
if (hasToggledState) SemanticsFlag.hasToggledState,
|
||||
if (isToggled) SemanticsFlag.isToggled,
|
||||
if (hasImplicitScrolling) SemanticsFlag.hasImplicitScrolling,
|
||||
];
|
||||
|
||||
final List<SemanticsAction> actions = <SemanticsAction>[];
|
||||
if (hasTapAction)
|
||||
actions.add(SemanticsAction.tap);
|
||||
if (hasLongPressAction)
|
||||
actions.add(SemanticsAction.longPress);
|
||||
if (hasScrollLeftAction)
|
||||
actions.add(SemanticsAction.scrollLeft);
|
||||
if (hasScrollRightAction)
|
||||
actions.add(SemanticsAction.scrollRight);
|
||||
if (hasScrollUpAction)
|
||||
actions.add(SemanticsAction.scrollUp);
|
||||
if (hasScrollDownAction)
|
||||
actions.add(SemanticsAction.scrollDown);
|
||||
if (hasIncreaseAction)
|
||||
actions.add(SemanticsAction.increase);
|
||||
if (hasDecreaseAction)
|
||||
actions.add(SemanticsAction.decrease);
|
||||
if (hasShowOnScreenAction)
|
||||
actions.add(SemanticsAction.showOnScreen);
|
||||
if (hasMoveCursorForwardByCharacterAction)
|
||||
actions.add(SemanticsAction.moveCursorForwardByCharacter);
|
||||
if (hasMoveCursorBackwardByCharacterAction)
|
||||
actions.add(SemanticsAction.moveCursorBackwardByCharacter);
|
||||
if (hasSetSelectionAction)
|
||||
actions.add(SemanticsAction.setSelection);
|
||||
if (hasCopyAction)
|
||||
actions.add(SemanticsAction.copy);
|
||||
if (hasCutAction)
|
||||
actions.add(SemanticsAction.cut);
|
||||
if (hasPasteAction)
|
||||
actions.add(SemanticsAction.paste);
|
||||
if (hasDidGainAccessibilityFocusAction)
|
||||
actions.add(SemanticsAction.didGainAccessibilityFocus);
|
||||
if (hasDidLoseAccessibilityFocusAction)
|
||||
actions.add(SemanticsAction.didLoseAccessibilityFocus);
|
||||
if (customActions != null && customActions.isNotEmpty)
|
||||
actions.add(SemanticsAction.customAction);
|
||||
if (hasDismissAction)
|
||||
actions.add(SemanticsAction.dismiss);
|
||||
if (hasMoveCursorForwardByWordAction)
|
||||
actions.add(SemanticsAction.moveCursorForwardByWord);
|
||||
if (hasMoveCursorBackwardByWordAction)
|
||||
actions.add(SemanticsAction.moveCursorBackwardByWord);
|
||||
final List<SemanticsAction> actions = <SemanticsAction>[
|
||||
if (hasTapAction) SemanticsAction.tap,
|
||||
if (hasLongPressAction) SemanticsAction.longPress,
|
||||
if (hasScrollLeftAction) SemanticsAction.scrollLeft,
|
||||
if (hasScrollRightAction) SemanticsAction.scrollRight,
|
||||
if (hasScrollUpAction) SemanticsAction.scrollUp,
|
||||
if (hasScrollDownAction) SemanticsAction.scrollDown,
|
||||
if (hasIncreaseAction) SemanticsAction.increase,
|
||||
if (hasDecreaseAction) SemanticsAction.decrease,
|
||||
if (hasShowOnScreenAction) SemanticsAction.showOnScreen,
|
||||
if (hasMoveCursorForwardByCharacterAction) SemanticsAction.moveCursorForwardByCharacter,
|
||||
if (hasMoveCursorBackwardByCharacterAction) SemanticsAction.moveCursorBackwardByCharacter,
|
||||
if (hasSetSelectionAction) SemanticsAction.setSelection,
|
||||
if (hasCopyAction) SemanticsAction.copy,
|
||||
if (hasCutAction) SemanticsAction.cut,
|
||||
if (hasPasteAction) SemanticsAction.paste,
|
||||
if (hasDidGainAccessibilityFocusAction) SemanticsAction.didGainAccessibilityFocus,
|
||||
if (hasDidLoseAccessibilityFocusAction) SemanticsAction.didLoseAccessibilityFocus,
|
||||
if (customActions != null && customActions.isNotEmpty) SemanticsAction.customAction,
|
||||
if (hasDismissAction) SemanticsAction.dismiss,
|
||||
if (hasMoveCursorForwardByWordAction) SemanticsAction.moveCursorForwardByWord,
|
||||
if (hasMoveCursorBackwardByWordAction) SemanticsAction.moveCursorBackwardByWord,
|
||||
];
|
||||
SemanticsHintOverrides hintOverrides;
|
||||
if (onTapHint != null || onLongPressHint != null)
|
||||
hintOverrides = SemanticsHintOverrides(
|
||||
@ -1883,11 +1843,11 @@ class _MatchesSemanticsData extends Matcher {
|
||||
for (SemanticsAction action in actions)
|
||||
actionBits |= action.index;
|
||||
if (actionBits != data.actions) {
|
||||
final List<String> actionSummary = <String>[];
|
||||
for (SemanticsAction action in SemanticsAction.values.values) {
|
||||
if ((data.actions & action.index) != 0)
|
||||
actionSummary.add(describeEnum(action));
|
||||
}
|
||||
final List<String> actionSummary = <String>[
|
||||
for (SemanticsAction action in SemanticsAction.values.values)
|
||||
if ((data.actions & action.index) != 0)
|
||||
describeEnum(action),
|
||||
];
|
||||
return failWithDescription(matchState, 'actions were: $actionSummary');
|
||||
}
|
||||
}
|
||||
@ -1917,11 +1877,11 @@ class _MatchesSemanticsData extends Matcher {
|
||||
for (SemanticsFlag flag in flags)
|
||||
flagBits |= flag.index;
|
||||
if (flagBits != data.flags) {
|
||||
final List<String> flagSummary = <String>[];
|
||||
for (SemanticsFlag flag in SemanticsFlag.values.values) {
|
||||
if ((data.flags & flag.index) != 0)
|
||||
flagSummary.add(describeEnum(flag));
|
||||
}
|
||||
final List<String> flagSummary = <String>[
|
||||
for (SemanticsFlag flag in SemanticsFlag.values.values)
|
||||
if ((data.flags & flag.index) != 0)
|
||||
describeEnum(flag),
|
||||
];
|
||||
return failWithDescription(matchState, 'flags were: $flagSummary');
|
||||
}
|
||||
}
|
||||
|
@ -185,9 +185,10 @@ class TestAsyncUtils {
|
||||
assert(candidateScope.zone != null);
|
||||
} while (candidateScope.zone != zone);
|
||||
assert(scope != null);
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[];
|
||||
information.add(ErrorSummary('Guarded function conflict.'));
|
||||
information.add(ErrorHint('You must use "await" with all Future-returning test APIs.'));
|
||||
final List<DiagnosticsNode> information = <DiagnosticsNode>[
|
||||
ErrorSummary('Guarded function conflict.'),
|
||||
ErrorHint('You must use "await" with all Future-returning test APIs.'),
|
||||
];
|
||||
final _StackEntry originalGuarder = _findResponsibleMethod(scope.creationStack, 'guard', information);
|
||||
final _StackEntry collidingGuarder = _findResponsibleMethod(StackTrace.current, 'guardSync', information);
|
||||
if (originalGuarder != null && collidingGuarder != null) {
|
||||
|
@ -73,11 +73,10 @@ String getAvdPath() {
|
||||
|
||||
final List<String> searchPaths = <String>[
|
||||
platform.environment['ANDROID_AVD_HOME'],
|
||||
if (platform.environment['HOME'] != null)
|
||||
fs.path.join(platform.environment['HOME'], '.android', 'avd'),
|
||||
];
|
||||
|
||||
if (platform.environment['HOME'] != null) {
|
||||
searchPaths.add(fs.path.join(platform.environment['HOME'], '.android', 'avd'));
|
||||
}
|
||||
|
||||
if (platform.isWindows) {
|
||||
final String homeDrive = platform.environment['HOMEDRIVE'];
|
||||
|
@ -236,13 +236,13 @@ Future<GradleProject> _readGradleProject({bool isLibrary = false}) async {
|
||||
// flavors and build types defined in the project. If gradle fails, then check if the failure is due to t
|
||||
try {
|
||||
final RunResult propertiesRunResult = await processUtils.run(
|
||||
<String>[gradlew, isLibrary ? 'properties' : 'app:properties'],
|
||||
<String>[gradlew, if (isLibrary) 'properties' else 'app:properties'],
|
||||
throwOnError: true,
|
||||
workingDirectory: hostAppGradleRoot.path,
|
||||
environment: _gradleEnv,
|
||||
);
|
||||
final RunResult tasksRunResult = await processUtils.run(
|
||||
<String>[gradlew, isLibrary ? 'tasks': 'app:tasks', '--all', '--console=auto'],
|
||||
<String>[gradlew, if (isLibrary) 'tasks' else 'app:tasks', '--all', '--console=auto'],
|
||||
throwOnError: true,
|
||||
workingDirectory: hostAppGradleRoot.path,
|
||||
environment: _gradleEnv,
|
||||
|
@ -418,11 +418,10 @@ DevFSContent _createAssetManifest(Map<_Asset, List<_Asset>> assetVariants) {
|
||||
..sort(_byBasename);
|
||||
|
||||
for (_Asset main in sortedKeys) {
|
||||
final List<String> variants = <String>[];
|
||||
for (_Asset variant in assetVariants[main]) {
|
||||
variants.add(variant.entryUri.path);
|
||||
}
|
||||
jsonObject[main.entryUri.path] = variants;
|
||||
jsonObject[main.entryUri.path] = <String>[
|
||||
for (_Asset variant in assetVariants[main])
|
||||
variant.entryUri.path,
|
||||
];
|
||||
}
|
||||
return DevFSStringContent(json.encode(jsonObject));
|
||||
}
|
||||
|
@ -142,11 +142,11 @@ class _PosixUtils extends OperatingSystemUtils {
|
||||
|
||||
@override
|
||||
List<File> _which(String execName, { bool all = false }) {
|
||||
final List<String> command = <String>['which'];
|
||||
if (all) {
|
||||
command.add('-a');
|
||||
}
|
||||
command.add(execName);
|
||||
final List<String> command = <String>[
|
||||
'which',
|
||||
if (all) '-a',
|
||||
execName,
|
||||
];
|
||||
final ProcessResult result = processManager.runSync(command);
|
||||
if (result.exitCode != 0) {
|
||||
return const <File>[];
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user