Reland removal of examples/catalog (#67545)
@ -613,7 +613,6 @@ Future<void> _runFrameworkTests() async {
|
|||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), tableData: bigqueryApi?.tabledata);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'), tableData: bigqueryApi?.tabledata);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'), tableData: bigqueryApi?.tabledata);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'examples', 'catalog'), tableData: bigqueryApi?.tabledata);
|
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), tableData: bigqueryApi?.tabledata);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), tableData: bigqueryApi?.tabledata);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks'), tableData: bigqueryApi?.tabledata);
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks'), tableData: bigqueryApi?.tabledata);
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
Samples Catalog
|
|
||||||
=======
|
|
||||||
|
|
||||||
A collection of sample apps that demonstrate how Flutter can be used.
|
|
||||||
|
|
||||||
Each sample app is contained in a single `.dart` file located in the `lib`
|
|
||||||
directory. To run each sample app, specify the corresponding file on the
|
|
||||||
`flutter run` command line, for example:
|
|
||||||
|
|
||||||
```
|
|
||||||
flutter run lib/animated_list.dart
|
|
||||||
flutter run lib/app_bar_bottom.dart
|
|
||||||
flutter run lib/basic_app_bar.dart
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
The apps are intended to be short and easily understood. Classes that represent
|
|
||||||
the sample's focus are at the top of the file; data and support classes follow.
|
|
||||||
|
|
||||||
Each sample app contains a comment (usually at the end) which provides some
|
|
||||||
standard documentation that also appears in the web view of the catalog.
|
|
||||||
See the "Generating..." section below.
|
|
||||||
|
|
||||||
Generating the web view of the catalog
|
|
||||||
---------
|
|
||||||
|
|
||||||
Markdown and a screenshot of each app are produced by `bin/sample_page.dart`
|
|
||||||
and saved in the `.generated` directory. The markdown file contains
|
|
||||||
the text taken from the Sample Catalog comment found in the app's source
|
|
||||||
file, followed by the source code itself.
|
|
||||||
|
|
||||||
This `sample_page.dart` command-line app must be run from the `examples/catalog`
|
|
||||||
directory. It relies on templates also found in the bin directory, and it
|
|
||||||
generates and executes `test_driver` apps to collect the screenshots:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd examples/catalog
|
|
||||||
dart bin/sample_page.dart
|
|
||||||
```
|
|
@ -1,57 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
def localProperties = new Properties()
|
|
||||||
def localPropertiesFile = rootProject.file('local.properties')
|
|
||||||
if (localPropertiesFile.exists()) {
|
|
||||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
|
||||||
localProperties.load(reader)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
|
||||||
if (flutterRoot == null) {
|
|
||||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
|
||||||
if (flutterVersionCode == null) {
|
|
||||||
flutterVersionCode = '1'
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
|
||||||
if (flutterVersionName == null) {
|
|
||||||
flutterVersionName = '1.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 29
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
disable 'InvalidPackage'
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "io.flutter.examples.catalog"
|
|
||||||
minSdkVersion 16
|
|
||||||
targetSdkVersion 29
|
|
||||||
versionCode flutterVersionCode.toInteger()
|
|
||||||
versionName flutterVersionName
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
// TODO: Add your own signing config for the release build.
|
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig signingConfigs.debug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flutter {
|
|
||||||
source '../..'
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
<!-- Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
Use of this source code is governed by a BSD-style license that can be
|
|
||||||
found in the LICENSE file. -->
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.yourcompany.animated_list">
|
|
||||||
|
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
|
||||||
flutter needs it to communicate with the running application
|
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
|
||||||
-->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
|
|
||||||
<application android:label="animated_list" android:icon="@mipmap/ic_launcher">
|
|
||||||
<activity android:name="io.flutter.embedding.android.FlutterActivity"
|
|
||||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:windowSoftInputMode="adjustResize">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<!-- Don't delete the meta-data below.
|
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
|
||||||
<meta-data
|
|
||||||
android:name="flutterEmbedding"
|
|
||||||
android:value="2" />
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
Before Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.4 KiB |
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.buildDir = '../build'
|
|
||||||
subprojects {
|
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(':app')
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
|
||||||
android.useAndroidX=true
|
|
||||||
android.enableJetifier=true
|
|
||||||
android.enableR8=true
|
|
@ -1,6 +0,0 @@
|
|||||||
#Fri Jun 23 08:50:38 CEST 2017
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
include ':app'
|
|
||||||
|
|
||||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
|
||||||
def properties = new Properties()
|
|
||||||
|
|
||||||
assert localPropertiesFile.exists()
|
|
||||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
|
||||||
|
|
||||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
|
||||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
|
||||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
|
@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
layout: page
|
|
||||||
title: "@(class) Sample Apps"
|
|
||||||
permalink: /catalog/samples/@(link)/
|
|
||||||
---
|
|
||||||
|
|
||||||
All of the sample apps listed here use the Flutter @(class) class in an interesting way. The <a href="/catalog/samples/">Sample App Catalog</a> page lists all of the sample apps.
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
@(entries)
|
|
||||||
</div>
|
|
@ -1,18 +0,0 @@
|
|||||||
<div class="row" style="margin-bottom: 32px">
|
|
||||||
<a href="/catalog/samples/@(link)/">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<img style="border:1px solid #000000" src="@(android screenshot)" alt="Android screenshot" class="img-responsive">
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<div class="col-md-9">
|
|
||||||
<p>
|
|
||||||
@(summary)
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
This app features the following classes: @(classes).
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="/catalog/samples/@(link)/">Learn more</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
layout: page
|
|
||||||
title: "Sample App Catalog"
|
|
||||||
permalink: /catalog/samples/
|
|
||||||
---
|
|
||||||
|
|
||||||
This catalog lists applications that demonstrate how to implement common mobile design patterns with Flutter. Each sample demonstrates how a few Flutter widgets can be put together to implement a meaningful user interface. The samples are short - just one Dart file - but they're complete applications. They should be easy to try out and tweak with your favorite IDE/code editor.
|
|
||||||
|
|
||||||
If there are other sample apps that you'd like to see we'd appreciate hearing from you on our [Gitter channel](https://gitter.im/flutter/flutter) or [mailing list](https://groups.google.com/d/forum/flutter-dev).
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
@(entries)
|
|
||||||
</div>
|
|
@ -1,264 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// This application generates markdown pages and screenshots for each
|
|
||||||
// sample app. For more information see ../README.md.
|
|
||||||
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:path/path.dart';
|
|
||||||
|
|
||||||
class SampleError extends Error {
|
|
||||||
SampleError(this.message);
|
|
||||||
final String message;
|
|
||||||
@override
|
|
||||||
String toString() => 'SampleError($message)';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample apps are .dart files in the lib directory which contain a block
|
|
||||||
// comment that begins with a '/* Sample Catalog' line, and ends with a line
|
|
||||||
// that just contains '*/'. The following keywords may appear at the
|
|
||||||
// beginning of lines within the comment. A keyword's value is all of
|
|
||||||
// the following text up to the next keyword or the end of the comment,
|
|
||||||
// sans leading and trailing whitespace.
|
|
||||||
const String sampleCatalogKeywords = r'^Title:|^Summary:|^Description:|^Classes:|^Sample:|^See also:';
|
|
||||||
|
|
||||||
Directory outputDirectory;
|
|
||||||
Directory sampleDirectory;
|
|
||||||
Directory testDirectory;
|
|
||||||
Directory driverDirectory;
|
|
||||||
|
|
||||||
void logMessage(String s) { print(s); }
|
|
||||||
void logError(String s) { print(s); }
|
|
||||||
|
|
||||||
File inputFile(String dir, String name) {
|
|
||||||
return File(dir + Platform.pathSeparator + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
File outputFile(String name, [Directory directory]) {
|
|
||||||
return File((directory ?? outputDirectory).path + Platform.pathSeparator + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initialize() {
|
|
||||||
outputDirectory = Directory('.generated');
|
|
||||||
sampleDirectory = Directory('lib');
|
|
||||||
testDirectory = Directory('test');
|
|
||||||
driverDirectory = Directory('test_driver');
|
|
||||||
outputDirectory.createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a copy of template with each occurrence of @(foo) replaced
|
|
||||||
// by values[foo].
|
|
||||||
String expandTemplate(String template, Map<String, String> values) {
|
|
||||||
// Matches @(foo), match[1] == 'foo'
|
|
||||||
final RegExp tokenRE = RegExp(r'@\(([\w ]+)\)', multiLine: true);
|
|
||||||
return template.replaceAllMapped(tokenRE, (Match match) {
|
|
||||||
if (match.groupCount != 1)
|
|
||||||
throw SampleError('bad template keyword $match[0]');
|
|
||||||
final String keyword = match[1];
|
|
||||||
return values[keyword] ?? '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeExpandedTemplate(File output, String template, Map<String, String> values) {
|
|
||||||
output.writeAsStringSync(expandTemplate(template, values));
|
|
||||||
logMessage('wrote $output');
|
|
||||||
}
|
|
||||||
|
|
||||||
class SampleInfo {
|
|
||||||
SampleInfo(this.sourceFile, this.commit);
|
|
||||||
|
|
||||||
final File sourceFile;
|
|
||||||
final String commit;
|
|
||||||
String sourceCode;
|
|
||||||
Map<String, String> commentValues;
|
|
||||||
|
|
||||||
// If sourceFile is lib/foo.dart then sourceName is foo. The sourceName
|
|
||||||
// is used to create derived filenames like foo.md or foo.png.
|
|
||||||
String get sourceName => basenameWithoutExtension(sourceFile.path);
|
|
||||||
|
|
||||||
// The website's link to this page will be /catalog/samples/@(link)/.
|
|
||||||
String get link => sourceName.replaceAll('_', '-');
|
|
||||||
|
|
||||||
// The name of the widget class that defines this sample app, like 'FooSample'.
|
|
||||||
String get sampleClass => commentValues['sample'];
|
|
||||||
|
|
||||||
// The value of the 'Classes:' comment as a list of class names.
|
|
||||||
Iterable<String> get highlightedClasses {
|
|
||||||
final String classNames = commentValues['classes'];
|
|
||||||
if (classNames == null)
|
|
||||||
return const <String>[];
|
|
||||||
return classNames.split(',').map<String>((String s) => s.trim()).where((String s) => s.isNotEmpty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The relative import path for this sample, like '../lib/foo.dart'.
|
|
||||||
String get importPath => '..' + Platform.pathSeparator + sourceFile.path;
|
|
||||||
|
|
||||||
// Return true if we're able to find the "Sample Catalog" comment in the
|
|
||||||
// sourceFile, and we're able to load its keyword/value pairs into
|
|
||||||
// the commentValues Map. The rest of the file's contents are saved
|
|
||||||
// in sourceCode.
|
|
||||||
bool initialize() {
|
|
||||||
final String contents = sourceFile.readAsStringSync();
|
|
||||||
|
|
||||||
final RegExp startRE = RegExp(r'^/\*\s+^Sample\s+Catalog', multiLine: true);
|
|
||||||
final RegExp endRE = RegExp(r'^\*/', multiLine: true);
|
|
||||||
final Match startMatch = startRE.firstMatch(contents);
|
|
||||||
if (startMatch == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
final int startIndex = startMatch.end;
|
|
||||||
final Match endMatch = endRE.firstMatch(contents.substring(startIndex));
|
|
||||||
if (endMatch == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
final String comment = contents.substring(startIndex, startIndex + endMatch.start);
|
|
||||||
sourceCode = contents.substring(0, startMatch.start) + contents.substring(startIndex + endMatch.end);
|
|
||||||
if (sourceCode.trim().isEmpty)
|
|
||||||
throw SampleError('did not find any source code in $sourceFile');
|
|
||||||
|
|
||||||
final RegExp keywordsRE = RegExp(sampleCatalogKeywords, multiLine: true);
|
|
||||||
final List<Match> keywordMatches = keywordsRE.allMatches(comment).toList();
|
|
||||||
if (keywordMatches.isEmpty)
|
|
||||||
throw SampleError('did not find any keywords in the Sample Catalog comment in $sourceFile');
|
|
||||||
|
|
||||||
commentValues = <String, String>{};
|
|
||||||
for (int i = 0; i < keywordMatches.length; i += 1) {
|
|
||||||
final String keyword = comment.substring(keywordMatches[i].start, keywordMatches[i].end - 1);
|
|
||||||
final String value = comment.substring(
|
|
||||||
keywordMatches[i].end,
|
|
||||||
i == keywordMatches.length - 1 ? null : keywordMatches[i + 1].start,
|
|
||||||
);
|
|
||||||
commentValues[keyword.toLowerCase()] = value.trim();
|
|
||||||
}
|
|
||||||
commentValues['name'] = sourceName;
|
|
||||||
commentValues['path'] = 'examples/catalog/${sourceFile.path}';
|
|
||||||
commentValues['source'] = sourceCode.trim();
|
|
||||||
commentValues['link'] = link;
|
|
||||||
commentValues['android screenshot'] = 'https://storage.googleapis.com/flutter-catalog/$commit/${sourceName}_small.png';
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate(String commit) {
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
final List<SampleInfo> samples = <SampleInfo>[];
|
|
||||||
for (final FileSystemEntity entity in sampleDirectory.listSync()) {
|
|
||||||
if (entity is File && entity.path.endsWith('.dart')) {
|
|
||||||
final SampleInfo sample = SampleInfo(entity, commit);
|
|
||||||
if (sample.initialize()) // skip files that lack the Sample Catalog comment
|
|
||||||
samples.add(sample);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Causes the generated imports to appear in alphabetical order.
|
|
||||||
// Avoid complaints from flutter lint.
|
|
||||||
samples.sort((SampleInfo a, SampleInfo b) {
|
|
||||||
return a.sourceName.compareTo(b.sourceName);
|
|
||||||
});
|
|
||||||
|
|
||||||
final String entryTemplate = inputFile('bin', 'entry.md.template').readAsStringSync();
|
|
||||||
|
|
||||||
// Write the sample catalog's home page: index.md
|
|
||||||
final Iterable<String> entries = samples.map<String>((SampleInfo sample) {
|
|
||||||
return expandTemplate(entryTemplate, sample.commentValues);
|
|
||||||
});
|
|
||||||
writeExpandedTemplate(
|
|
||||||
outputFile('index.md'),
|
|
||||||
inputFile('bin', 'index.md.template').readAsStringSync(),
|
|
||||||
<String, String>{
|
|
||||||
'entries': entries.join('\n'),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Write the sample app files, like animated_list.md
|
|
||||||
for (final SampleInfo sample in samples) {
|
|
||||||
writeExpandedTemplate(
|
|
||||||
outputFile(sample.sourceName + '.md'),
|
|
||||||
inputFile('bin', 'sample_page.md.template').readAsStringSync(),
|
|
||||||
sample.commentValues,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each unique class listened in a sample app's "Classes:" list, generate
|
|
||||||
// a file that's structurally the same as index.md but only contains samples
|
|
||||||
// that feature one class. For example AnimatedList_index.md would only
|
|
||||||
// include samples that had AnimatedList in their "Classes:" list.
|
|
||||||
final Map<String, List<SampleInfo>> classToSamples = <String, List<SampleInfo>>{};
|
|
||||||
for (final SampleInfo sample in samples) {
|
|
||||||
for (final String className in sample.highlightedClasses) {
|
|
||||||
classToSamples[className] ??= <SampleInfo>[];
|
|
||||||
classToSamples[className].add(sample);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (final String className in classToSamples.keys) {
|
|
||||||
final Iterable<String> entries = classToSamples[className].map<String>((SampleInfo sample) {
|
|
||||||
return expandTemplate(entryTemplate, sample.commentValues);
|
|
||||||
});
|
|
||||||
writeExpandedTemplate(
|
|
||||||
outputFile('${className}_index.md'),
|
|
||||||
inputFile('bin', 'class_index.md.template').readAsStringSync(),
|
|
||||||
<String, String>{
|
|
||||||
'class': className,
|
|
||||||
'entries': entries.join('\n'),
|
|
||||||
'link': '${className}_index',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write screenshot.dart, a "test" app that displays each sample
|
|
||||||
// app in turn when the app is tapped.
|
|
||||||
writeExpandedTemplate(
|
|
||||||
outputFile('screenshot.dart', driverDirectory),
|
|
||||||
inputFile('bin', 'screenshot.dart.template').readAsStringSync(),
|
|
||||||
<String, String>{
|
|
||||||
'imports': samples.map<String>((SampleInfo page) {
|
|
||||||
return "import '${page.importPath}' show ${page.sampleClass};\n";
|
|
||||||
}).join(),
|
|
||||||
'widgets': samples.map<String>((SampleInfo sample) {
|
|
||||||
return 'new ${sample.sampleClass}(),\n';
|
|
||||||
}).join(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Write screenshot_test.dart, a test driver for screenshot.dart
|
|
||||||
// that collects screenshots of each app and saves them.
|
|
||||||
writeExpandedTemplate(
|
|
||||||
outputFile('screenshot_test.dart', driverDirectory),
|
|
||||||
inputFile('bin', 'screenshot_test.dart.template').readAsStringSync(),
|
|
||||||
<String, String>{
|
|
||||||
'paths': samples.map<String>((SampleInfo sample) {
|
|
||||||
return "'${outputFile(sample.sourceName + '.png').path}'";
|
|
||||||
}).join(',\n'),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// For now, the website's index.json file must be updated by hand.
|
|
||||||
logMessage('The following entries must appear in _data/catalog/widgets.json');
|
|
||||||
for (final String className in classToSamples.keys)
|
|
||||||
logMessage('"sample": "${className}_index"');
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(List<String> args) {
|
|
||||||
if (args.length != 1) {
|
|
||||||
logError(
|
|
||||||
'Usage (cd examples/catalog/; dart bin/sample_page.dart commit)\n'
|
|
||||||
'The flutter commit hash locates screenshots on storage.googleapis.com/flutter-catalog/'
|
|
||||||
);
|
|
||||||
exit(255);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
generate(args[0]);
|
|
||||||
} catch (error) {
|
|
||||||
logError(
|
|
||||||
'Error: sample_page.dart failed: $error\n'
|
|
||||||
'This sample_page.dart app expects to be run from the examples/catalog directory. '
|
|
||||||
'More information can be found in examples/catalog/README.md.'
|
|
||||||
);
|
|
||||||
exit(255);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
---
|
|
||||||
layout: page
|
|
||||||
title: "@(title)"
|
|
||||||
permalink: /catalog/samples/@(link)/
|
|
||||||
---
|
|
||||||
|
|
||||||
@(summary)
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-body" style="padding: 16px 32px;">
|
|
||||||
<img style="border:1px solid #000000" src="@(android screenshot)" alt="Android screenshot" class="img-responsive">
|
|
||||||
</div>
|
|
||||||
<div class="panel-footer">
|
|
||||||
Android screenshot
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
@(description)
|
|
||||||
|
|
||||||
Try this app out by creating a new project with `flutter create` and replacing the contents of `lib/main.dart` with the code that follows.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
@(source)
|
|
||||||
```
|
|
||||||
|
|
||||||
<h2>See also:</h2>
|
|
||||||
@(see also)
|
|
||||||
- The source code in [@(path)](https://github.com/flutter/flutter/blob/master/@(path)).
|
|
@ -1,41 +0,0 @@
|
|||||||
// This file was generated using bin/screenshot.dart.template and
|
|
||||||
// bin/sample_page.dart. For more information see README.md.
|
|
||||||
|
|
||||||
import 'package:flutter_driver/driver_extension.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
@(imports)
|
|
||||||
|
|
||||||
class SampleScreenshots extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
SampleScreenshotsState createState() => new SampleScreenshotsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class SampleScreenshotsState extends State<SampleScreenshots> {
|
|
||||||
final List<Widget> samples = <Widget>[
|
|
||||||
@(widgets)
|
|
||||||
];
|
|
||||||
int sampleIndex = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return new GestureDetector(
|
|
||||||
key: const ValueKey<String>('screenshotGestureDetector'),
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
sampleIndex += 1;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: new IgnorePointer(
|
|
||||||
child: samples[sampleIndex % samples.length],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
enableFlutterDriverExtension();
|
|
||||||
WidgetsApp.debugAllowBannerOverride = false; // No "debug" banner.
|
|
||||||
runApp(new SampleScreenshots());
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
// This file was generated using bin/screenshot_test.dart.template and
|
|
||||||
// bin/sample_page.dart. For more information see README.md.
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter_driver/flutter_driver.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group('sample screenshots', () {
|
|
||||||
FlutterDriver driver;
|
|
||||||
|
|
||||||
setUpAll(() async {
|
|
||||||
driver = await FlutterDriver.connect();
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await driver?.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('take sample screenshots', () async {
|
|
||||||
final List<String> paths = <String>[
|
|
||||||
@(paths)
|
|
||||||
];
|
|
||||||
for (String path in paths) {
|
|
||||||
await driver.waitUntilNoTransientCallbacks();
|
|
||||||
final List<int> pixels = await driver.screenshot();
|
|
||||||
final File file = new File(path);
|
|
||||||
await file.writeAsBytes(pixels);
|
|
||||||
print('wrote $file');
|
|
||||||
await driver.tap(find.byValueKey('screenshotGestureDetector'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>io.flutter.flutter.app</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>App</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>MinimumOSVersion</key>
|
|
||||||
<string>9.0</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
@ -1 +0,0 @@
|
|||||||
#include "Generated.xcconfig"
|
|
@ -1,503 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 46;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
|
||||||
74970F651EDBF3AE000507F3 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 74970F641EDBF3AE000507F3 /* GeneratedPluginRegistrant.m */; };
|
|
||||||
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
|
|
||||||
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 10;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
name = "Embed Frameworks";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
|
||||||
74970F631EDBF3AE000507F3 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
|
||||||
74970F641EDBF3AE000507F3 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
|
||||||
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
|
||||||
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
|
||||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
840012C8B5EDBCF56B0E4AC1 /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Flutter;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146E51CF9000F007C117D = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
|
||||||
840012C8B5EDBCF56B0E4AC1 /* Pods */,
|
|
||||||
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
|
|
||||||
);
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146EF1CF9000F007C117D /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
74970F631EDBF3AE000507F3 /* GeneratedPluginRegistrant.h */,
|
|
||||||
74970F641EDBF3AE000507F3 /* GeneratedPluginRegistrant.m */,
|
|
||||||
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
|
|
||||||
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
|
||||||
97C146F11CF9000F007C117D /* Supporting Files */,
|
|
||||||
);
|
|
||||||
path = Runner;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146F11CF9000F007C117D /* Supporting Files */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
97C146F21CF9000F007C117D /* main.m */,
|
|
||||||
);
|
|
||||||
name = "Supporting Files";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
|
||||||
buildPhases = (
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = Runner;
|
|
||||||
productName = Runner;
|
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
|
||||||
productType = "com.apple.product-type.application";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
LastUpgradeCheck = 1020;
|
|
||||||
ORGANIZATIONNAME = "The Flutter Authors";
|
|
||||||
TargetAttributes = {
|
|
||||||
97C146ED1CF9000F007C117D = {
|
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
|
||||||
compatibilityVersion = "Xcode 3.2";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Thin Binary";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
|
||||||
};
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Run Script";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
|
|
||||||
97C146F31CF9000F007C117D /* main.m in Sources */,
|
|
||||||
74970F651EDBF3AE000507F3 /* GeneratedPluginRegistrant.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C146FB1CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = Main.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
97C147001CF9000F007C117D /* Base */,
|
|
||||||
);
|
|
||||||
name = LaunchScreen.storyboard;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
24FC0D0321828CE100FD135A /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
24FC0D0421828CE100FD135A /* Profile */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.animatedList;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
};
|
|
||||||
name = Profile;
|
|
||||||
};
|
|
||||||
97C147031CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147041CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
97C147061CF9000F007C117D /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.animatedList;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
97C147071CF9000F007C117D /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
|
||||||
buildSettings = {
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
ENABLE_BITCODE = NO;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.animatedList;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147031CF9000F007C117D /* Debug */,
|
|
||||||
97C147041CF9000F007C117D /* Release */,
|
|
||||||
24FC0D0321828CE100FD135A /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
97C147061CF9000F007C117D /* Debug */,
|
|
||||||
97C147071CF9000F007C117D /* Release */,
|
|
||||||
24FC0D0421828CE100FD135A /* Profile */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:Runner.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,91 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1020"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
|
||||||
BuildableName = "Runner.app"
|
|
||||||
BlueprintName = "Runner"
|
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:Runner.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
@ -1,10 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#import <Flutter/Flutter.h>
|
|
||||||
|
|
||||||
@interface AppDelegate : FlutterAppDelegate
|
|
||||||
|
|
||||||
@end
|
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
|
||||||
#import "GeneratedPluginRegistrant.h"
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
|
||||||
[GeneratedPluginRegistrant registerWithRegistry:self];
|
|
||||||
// Override point for customization after application launch.
|
|
||||||
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
||||||
}
|
|
||||||
@end
|
|
@ -1,116 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-20x20@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-29x29@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-40x40@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-App-60x60@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "20x20",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@1x.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-76x76@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "83.5x83.5",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 564 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.5 KiB |
@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="EHf-IW-A2E">
|
|
||||||
<objects>
|
|
||||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
|
||||||
<layoutGuides>
|
|
||||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
|
|
||||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
|
|
||||||
</layoutGuides>
|
|
||||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="53" y="375"/>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
</document>
|
|
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="iOS"/>
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--Flutter View Controller-->
|
|
||||||
<scene sceneID="tne-QT-ifu">
|
|
||||||
<objects>
|
|
||||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
|
||||||
<layoutGuides>
|
|
||||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
|
||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
|
||||||
</layoutGuides>
|
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
</document>
|
|
@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>animated_list</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
|
||||||
<true/>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<key>UIMainStoryboardFile</key>
|
|
||||||
<string>Main</string>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,14 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
#import <Flutter/Flutter.h>
|
|
||||||
#import "AppDelegate.h"
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
|
||||||
@autoreleasepool {
|
|
||||||
return UIApplicationMain(argc, argv, nil,
|
|
||||||
NSStringFromClass([AppDelegate class]));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,227 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class AnimatedListSample extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_AnimatedListSampleState createState() => _AnimatedListSampleState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AnimatedListSampleState extends State<AnimatedListSample> {
|
|
||||||
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
|
|
||||||
ListModel<int> _list;
|
|
||||||
int _selectedItem;
|
|
||||||
int _nextItem; // The next item inserted when the user presses the '+' button.
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_list = ListModel<int>(
|
|
||||||
listKey: _listKey,
|
|
||||||
initialItems: <int>[0, 1, 2],
|
|
||||||
removedItemBuilder: _buildRemovedItem,
|
|
||||||
);
|
|
||||||
_nextItem = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to build list items that haven't been removed.
|
|
||||||
Widget _buildItem(BuildContext context, int index, Animation<double> animation) {
|
|
||||||
return CardItem(
|
|
||||||
animation: animation,
|
|
||||||
item: _list[index],
|
|
||||||
selected: _selectedItem == _list[index],
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
_selectedItem = _selectedItem == _list[index] ? null : _list[index];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to build an item after it has been removed from the list. This method is
|
|
||||||
// needed because a removed item remains visible until its animation has
|
|
||||||
// completed (even though it's gone as far this ListModel is concerned).
|
|
||||||
// The widget will be used by the [AnimatedListState.removeItem] method's
|
|
||||||
// [AnimatedListRemovedItemBuilder] parameter.
|
|
||||||
Widget _buildRemovedItem(int item, BuildContext context, Animation<double> animation) {
|
|
||||||
return CardItem(
|
|
||||||
animation: animation,
|
|
||||||
item: item,
|
|
||||||
selected: false,
|
|
||||||
// No gesture detector here: we don't want removed items to be interactive.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert the "next item" into the list model.
|
|
||||||
void _insert() {
|
|
||||||
final int index = _selectedItem == null ? _list.length : _list.indexOf(_selectedItem);
|
|
||||||
_list.insert(index, _nextItem++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the selected item from the list model.
|
|
||||||
void _remove() {
|
|
||||||
if (_selectedItem != null) {
|
|
||||||
_list.removeAt(_list.indexOf(_selectedItem));
|
|
||||||
setState(() {
|
|
||||||
_selectedItem = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('AnimatedList'),
|
|
||||||
actions: <Widget>[
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.add_circle),
|
|
||||||
onPressed: _insert,
|
|
||||||
tooltip: 'insert a new item',
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.remove_circle),
|
|
||||||
onPressed: _remove,
|
|
||||||
tooltip: 'remove the selected item',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: AnimatedList(
|
|
||||||
key: _listKey,
|
|
||||||
initialItemCount: _list.length,
|
|
||||||
itemBuilder: _buildItem,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Keeps a Dart List in sync with an AnimatedList.
|
|
||||||
///
|
|
||||||
/// The [insert] and [removeAt] methods apply to both the internal list and the
|
|
||||||
/// animated list that belongs to [listKey].
|
|
||||||
///
|
|
||||||
/// This class only exposes as much of the Dart List API as is needed by the
|
|
||||||
/// sample app. More list methods are easily added, however methods that mutate the
|
|
||||||
/// list must make the same changes to the animated list in terms of
|
|
||||||
/// [AnimatedListState.insertItem] and [AnimatedList.removeItem].
|
|
||||||
class ListModel<E> {
|
|
||||||
ListModel({
|
|
||||||
@required this.listKey,
|
|
||||||
@required this.removedItemBuilder,
|
|
||||||
Iterable<E> initialItems,
|
|
||||||
}) : assert(listKey != null),
|
|
||||||
assert(removedItemBuilder != null),
|
|
||||||
_items = initialItems?.toList() ?? <E>[];
|
|
||||||
|
|
||||||
final GlobalKey<AnimatedListState> listKey;
|
|
||||||
final Widget Function(E item, BuildContext context, Animation<double> animation) removedItemBuilder;
|
|
||||||
final List<E> _items;
|
|
||||||
|
|
||||||
AnimatedListState get _animatedList => listKey.currentState;
|
|
||||||
|
|
||||||
void insert(int index, E item) {
|
|
||||||
_items.insert(index, item);
|
|
||||||
_animatedList.insertItem(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
E removeAt(int index) {
|
|
||||||
final E removedItem = _items.removeAt(index);
|
|
||||||
if (removedItem != null) {
|
|
||||||
_animatedList.removeItem(index, (BuildContext context, Animation<double> animation) {
|
|
||||||
return removedItemBuilder(removedItem, context, animation);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return removedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get length => _items.length;
|
|
||||||
E operator [](int index) => _items[index];
|
|
||||||
int indexOf(E item) => _items.indexOf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Displays its integer item as 'item N' on a Card whose color is based on
|
|
||||||
/// the item's value. The text is displayed in bright green if selected is true.
|
|
||||||
/// This widget's height is based on the animation parameter, it varies
|
|
||||||
/// from 0 to 128 as the animation varies from 0.0 to 1.0.
|
|
||||||
class CardItem extends StatelessWidget {
|
|
||||||
const CardItem({
|
|
||||||
Key key,
|
|
||||||
@required this.animation,
|
|
||||||
this.onTap,
|
|
||||||
@required this.item,
|
|
||||||
this.selected = false,
|
|
||||||
}) : assert(animation != null),
|
|
||||||
assert(item != null && item >= 0),
|
|
||||||
assert(selected != null),
|
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
final Animation<double> animation;
|
|
||||||
final VoidCallback onTap;
|
|
||||||
final int item;
|
|
||||||
final bool selected;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
TextStyle textStyle = Theme.of(context).textTheme.headline4;
|
|
||||||
if (selected)
|
|
||||||
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(2.0),
|
|
||||||
child: SizeTransition(
|
|
||||||
axis: Axis.vertical,
|
|
||||||
sizeFactor: animation,
|
|
||||||
child: GestureDetector(
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
onTap: onTap,
|
|
||||||
child: SizedBox(
|
|
||||||
height: 128.0,
|
|
||||||
child: Card(
|
|
||||||
color: Colors.primaries[item % Colors.primaries.length],
|
|
||||||
child: Center(
|
|
||||||
child: Text('Item $item', style: textStyle),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(AnimatedListSample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: AnimatedList
|
|
||||||
|
|
||||||
Summary: An AnimatedList for displaying a list of cards that stay
|
|
||||||
in sync with an app-specific ListModel. When an item is added to or removed
|
|
||||||
from the model, the corresponding card animates in or out of view.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
Tap an item to select it, tap it again to unselect. Tap '+' to insert at the
|
|
||||||
selected item, '-' to remove the selected item. The tap handlers add or
|
|
||||||
remove items from a `ListModel<E>`, a simple encapsulation of `List<E>`
|
|
||||||
that keeps the AnimatedList in sync. The list model has a GlobalKey for
|
|
||||||
its animated list. It uses the key to call the insertItem and removeItem
|
|
||||||
methods defined by AnimatedListState.
|
|
||||||
|
|
||||||
Classes: AnimatedList, AnimatedListState
|
|
||||||
|
|
||||||
Sample: AnimatedListSample
|
|
||||||
|
|
||||||
See also:
|
|
||||||
- The "Components-Lists: Controls" section of the material design specification:
|
|
||||||
<https://material.io/guidelines/components/lists-controls.html#>
|
|
||||||
*/
|
|
@ -1,145 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class AppBarBottomSample extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_AppBarBottomSampleState createState() => _AppBarBottomSampleState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppBarBottomSampleState extends State<AppBarBottomSample> with SingleTickerProviderStateMixin {
|
|
||||||
TabController _tabController;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_tabController = TabController(vsync: this, length: choices.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_tabController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _nextPage(int delta) {
|
|
||||||
final int newIndex = _tabController.index + delta;
|
|
||||||
if (newIndex < 0 || newIndex >= _tabController.length)
|
|
||||||
return;
|
|
||||||
_tabController.animateTo(newIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('AppBar Bottom Widget'),
|
|
||||||
leading: IconButton(
|
|
||||||
tooltip: 'Previous choice',
|
|
||||||
icon: const Icon(Icons.arrow_back),
|
|
||||||
onPressed: () { _nextPage(-1); },
|
|
||||||
),
|
|
||||||
actions: <Widget>[
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.arrow_forward),
|
|
||||||
tooltip: 'Next choice',
|
|
||||||
onPressed: () { _nextPage(1); },
|
|
||||||
),
|
|
||||||
],
|
|
||||||
bottom: PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(48.0),
|
|
||||||
child: Theme(
|
|
||||||
data: Theme.of(context).copyWith(accentColor: Colors.white),
|
|
||||||
child: Container(
|
|
||||||
height: 48.0,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: TabPageSelector(controller: _tabController),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: TabBarView(
|
|
||||||
controller: _tabController,
|
|
||||||
children: choices.map<Widget>((Choice choice) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: ChoiceCard(choice: choice),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Choice {
|
|
||||||
const Choice({ this.title, this.icon });
|
|
||||||
final String title;
|
|
||||||
final IconData icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
const List<Choice> choices = <Choice>[
|
|
||||||
Choice(title: 'CAR', icon: Icons.directions_car),
|
|
||||||
Choice(title: 'BICYCLE', icon: Icons.directions_bike),
|
|
||||||
Choice(title: 'BOAT', icon: Icons.directions_boat),
|
|
||||||
Choice(title: 'BUS', icon: Icons.directions_bus),
|
|
||||||
Choice(title: 'TRAIN', icon: Icons.directions_railway),
|
|
||||||
Choice(title: 'WALK', icon: Icons.directions_walk),
|
|
||||||
];
|
|
||||||
|
|
||||||
class ChoiceCard extends StatelessWidget {
|
|
||||||
const ChoiceCard({ Key key, this.choice }) : super(key: key);
|
|
||||||
|
|
||||||
final Choice choice;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final TextStyle textStyle = Theme.of(context).textTheme.headline4;
|
|
||||||
return Card(
|
|
||||||
color: Colors.white,
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(choice.icon, size: 128.0, color: textStyle.color),
|
|
||||||
Text(choice.title, style: textStyle),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(AppBarBottomSample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: AppBar with a custom bottom widget.
|
|
||||||
|
|
||||||
Summary: An AppBar that includes a bottom widget. Any widget
|
|
||||||
with a PreferredSize can appear at the bottom of an AppBar.
|
|
||||||
|
|
||||||
Summary: Any widget with a PreferredSize can appear at the bottom of an AppBar.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
Typically an AppBar's bottom widget is a TabBar however any widget with a
|
|
||||||
PreferredSize can be used. In this app, the app bar's bottom widget is a
|
|
||||||
TabPageSelector that displays the relative position of the selected page
|
|
||||||
in the app's TabBarView. The arrow buttons in the toolbar part of the app
|
|
||||||
bar and they select the previous or the next page.
|
|
||||||
|
|
||||||
Classes: AppBar, PreferredSize, TabBarView, TabController
|
|
||||||
|
|
||||||
Sample: AppBarBottomSample
|
|
||||||
|
|
||||||
See also:
|
|
||||||
- The "Components-Tabs" section of the material design specification:
|
|
||||||
<https://material.io/go/design-tabs>
|
|
||||||
*/
|
|
@ -1,121 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
// This app is a stateful, it tracks the user's current choice.
|
|
||||||
class BasicAppBarSample extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_BasicAppBarSampleState createState() => _BasicAppBarSampleState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BasicAppBarSampleState extends State<BasicAppBarSample> {
|
|
||||||
Choice _selectedChoice = choices[0]; // The app's "state".
|
|
||||||
|
|
||||||
void _select(Choice choice) {
|
|
||||||
setState(() { // Causes the app to rebuild with the new _selectedChoice.
|
|
||||||
_selectedChoice = choice;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Basic AppBar'),
|
|
||||||
actions: <Widget>[
|
|
||||||
IconButton( // action button
|
|
||||||
icon: Icon(choices[0].icon),
|
|
||||||
onPressed: () { _select(choices[0]); },
|
|
||||||
),
|
|
||||||
IconButton( // action button
|
|
||||||
icon: Icon(choices[1].icon),
|
|
||||||
onPressed: () { _select(choices[1]); },
|
|
||||||
),
|
|
||||||
PopupMenuButton<Choice>( // overflow menu
|
|
||||||
onSelected: _select,
|
|
||||||
itemBuilder: (BuildContext context) {
|
|
||||||
return choices.skip(2).map<PopupMenuItem<Choice>>((Choice choice) {
|
|
||||||
return PopupMenuItem<Choice>(
|
|
||||||
value: choice,
|
|
||||||
child: Text(choice.title),
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: ChoiceCard(choice: _selectedChoice),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Choice {
|
|
||||||
const Choice({ this.title, this.icon });
|
|
||||||
final String title;
|
|
||||||
final IconData icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
const List<Choice> choices = <Choice>[
|
|
||||||
Choice(title: 'Car', icon: Icons.directions_car),
|
|
||||||
Choice(title: 'Bicycle', icon: Icons.directions_bike),
|
|
||||||
Choice(title: 'Boat', icon: Icons.directions_boat),
|
|
||||||
Choice(title: 'Bus', icon: Icons.directions_bus),
|
|
||||||
Choice(title: 'Train', icon: Icons.directions_railway),
|
|
||||||
Choice(title: 'Walk', icon: Icons.directions_walk),
|
|
||||||
];
|
|
||||||
|
|
||||||
class ChoiceCard extends StatelessWidget {
|
|
||||||
const ChoiceCard({ Key key, this.choice }) : super(key: key);
|
|
||||||
|
|
||||||
final Choice choice;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final TextStyle textStyle = Theme.of(context).textTheme.headline4;
|
|
||||||
return Card(
|
|
||||||
color: Colors.white,
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(choice.icon, size: 128.0, color: textStyle.color),
|
|
||||||
Text(choice.title, style: textStyle),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(BasicAppBarSample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: AppBar Basics
|
|
||||||
|
|
||||||
Summary: A basic AppBar with a title, actions, and an overflow dropdown menu.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
An app that displays one of a half dozen choices with an icon and a title.
|
|
||||||
The two most common choices are available as action buttons and the remaining
|
|
||||||
choices are included in the overflow dropdown menu.
|
|
||||||
|
|
||||||
Classes: AppBar, IconButton, PopupMenuButton, Scaffold
|
|
||||||
|
|
||||||
Sample: BasicAppBarSample
|
|
||||||
|
|
||||||
See also:
|
|
||||||
- The "Layout-Structure" section of the material design specification:
|
|
||||||
<https://material.io/guidelines/layout/structure.html#structure-app-bar>
|
|
||||||
*/
|
|
@ -1,320 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/semantics.dart';
|
|
||||||
|
|
||||||
/// This example shows a set of widgets for changing data fields arranged in a
|
|
||||||
/// column of rows but, in accessibility mode, are traversed in a custom order.
|
|
||||||
///
|
|
||||||
/// This demonstrates how Flutter's accessibility system describes custom
|
|
||||||
/// traversal orders using sort keys.
|
|
||||||
///
|
|
||||||
/// The example app here has three fields that have a title and up/down spinner
|
|
||||||
/// buttons above and below. The traversal order should allow the user to focus
|
|
||||||
/// on each title, the input field next, the up spinner next, and the down
|
|
||||||
/// spinner last before moving to the next input title.
|
|
||||||
///
|
|
||||||
/// Users that do not use a screen reader (e.g. TalkBack on Android and
|
|
||||||
/// VoiceOver on iOS) will just see a regular app with controls.
|
|
||||||
///
|
|
||||||
/// The example's [RowColumnTraversal] widget sets up two [Semantics] objects
|
|
||||||
/// that wrap the given [Widget] child, providing the traversal order they
|
|
||||||
/// should have in the "row" direction, and then the traversal order they should
|
|
||||||
/// have in the "column" direction.
|
|
||||||
///
|
|
||||||
/// Since widgets are globally sorted by their sort key, the order does not have
|
|
||||||
/// to conform to the widget hierarchy. Indeed, in this example, we traverse
|
|
||||||
/// vertically first, but the widget hierarchy is a column of rows.
|
|
||||||
///
|
|
||||||
/// See also:
|
|
||||||
///
|
|
||||||
/// * [Semantics] for an object that annotates widgets with accessibility semantics
|
|
||||||
/// (including traversal order).
|
|
||||||
/// * [SemanticSortKey] for the base class of all semantic sort keys.
|
|
||||||
/// * [OrdinalSortKey] for a concrete sort key that sorts based on the given ordinal.
|
|
||||||
class RowColumnTraversal extends StatelessWidget {
|
|
||||||
const RowColumnTraversal({this.rowOrder, this.columnOrder, this.child});
|
|
||||||
|
|
||||||
final int rowOrder;
|
|
||||||
final int columnOrder;
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
/// Builds a widget hierarchy that wraps [child].
|
|
||||||
///
|
|
||||||
/// This function expresses the sort keys as a hierarchy.
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Semantics(
|
|
||||||
sortKey: OrdinalSortKey(columnOrder.toDouble()),
|
|
||||||
child: Semantics(
|
|
||||||
sortKey: OrdinalSortKey(rowOrder.toDouble()),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Component widgets ---------------------
|
|
||||||
|
|
||||||
/// A Button class that wraps an [IconButton] with a [RowColumnTraversal] to
|
|
||||||
/// set its traversal order.
|
|
||||||
class SpinnerButton extends StatelessWidget {
|
|
||||||
const SpinnerButton({
|
|
||||||
Key key,
|
|
||||||
this.onPressed,
|
|
||||||
this.icon,
|
|
||||||
this.rowOrder,
|
|
||||||
this.columnOrder,
|
|
||||||
this.field,
|
|
||||||
this.increment,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
final IconData icon;
|
|
||||||
final int rowOrder;
|
|
||||||
final int columnOrder;
|
|
||||||
final Field field;
|
|
||||||
final bool increment;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final String label = '${increment ? 'Increment' : 'Decrement'} ${_fieldToName(field)}';
|
|
||||||
|
|
||||||
return RowColumnTraversal(
|
|
||||||
rowOrder: rowOrder,
|
|
||||||
columnOrder: columnOrder,
|
|
||||||
child: Center(
|
|
||||||
child: IconButton(
|
|
||||||
icon: Icon(icon),
|
|
||||||
onPressed: onPressed,
|
|
||||||
tooltip: label,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A text entry field that wraps a [TextField] with a [RowColumnTraversal] to
|
|
||||||
/// set its traversal order.
|
|
||||||
class FieldWidget extends StatelessWidget {
|
|
||||||
const FieldWidget({
|
|
||||||
Key key,
|
|
||||||
this.rowOrder,
|
|
||||||
this.columnOrder,
|
|
||||||
this.onIncrease,
|
|
||||||
this.onDecrease,
|
|
||||||
this.value,
|
|
||||||
this.field,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final int rowOrder;
|
|
||||||
final int columnOrder;
|
|
||||||
final VoidCallback onDecrease;
|
|
||||||
final VoidCallback onIncrease;
|
|
||||||
final int value;
|
|
||||||
final Field field;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final String stringValue = '${_fieldToName(field)} $value';
|
|
||||||
final String increasedValue = '${_fieldToName(field)} ${value + 1}';
|
|
||||||
final String decreasedValue = '${_fieldToName(field)} ${value - 1}';
|
|
||||||
|
|
||||||
return RowColumnTraversal(
|
|
||||||
rowOrder: rowOrder,
|
|
||||||
columnOrder: columnOrder,
|
|
||||||
child: Center(
|
|
||||||
child: Semantics(
|
|
||||||
onDecrease: onDecrease,
|
|
||||||
onIncrease: onIncrease,
|
|
||||||
value: stringValue,
|
|
||||||
increasedValue: increasedValue,
|
|
||||||
decreasedValue: decreasedValue,
|
|
||||||
child: ExcludeSemantics(child: Text(value.toString())),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Field manipulation functions ---------------------
|
|
||||||
|
|
||||||
/// An enum that describes which column we're referring to.
|
|
||||||
enum Field { DOGS, CATS, FISH }
|
|
||||||
|
|
||||||
String _fieldToName(Field field) {
|
|
||||||
switch (field) {
|
|
||||||
case Field.DOGS:
|
|
||||||
return 'Dogs';
|
|
||||||
case Field.CATS:
|
|
||||||
return 'Cats';
|
|
||||||
case Field.FISH:
|
|
||||||
return 'Fish';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- Main app ---------------------
|
|
||||||
|
|
||||||
/// The top-level example widget that serves as the body of the app.
|
|
||||||
class CustomTraversalExample extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
CustomTraversalExampleState createState() => CustomTraversalExampleState();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The state object for the top level example widget.
|
|
||||||
class CustomTraversalExampleState extends State<CustomTraversalExample> {
|
|
||||||
/// The fields that we are manipulating. List indices correspond to
|
|
||||||
/// the entries in the [Field] enum.
|
|
||||||
List<int> fields = <int>[0, 0, 0];
|
|
||||||
|
|
||||||
void _addToField(Field field, int delta) {
|
|
||||||
setState(() {
|
|
||||||
fields[field.index] += delta;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _makeFieldHeader(int rowOrder, int columnOrder, Field field) {
|
|
||||||
return RowColumnTraversal(
|
|
||||||
rowOrder: rowOrder,
|
|
||||||
columnOrder: columnOrder,
|
|
||||||
child: Text(_fieldToName(field)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _makeSpinnerButton(int rowOrder, int columnOrder, Field field, {bool increment = true}) {
|
|
||||||
return SpinnerButton(
|
|
||||||
rowOrder: rowOrder,
|
|
||||||
columnOrder: columnOrder,
|
|
||||||
icon: increment ? Icons.arrow_upward : Icons.arrow_downward,
|
|
||||||
onPressed: () => _addToField(field, increment ? 1 : -1),
|
|
||||||
field: field,
|
|
||||||
increment: increment,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _makeEntryField(int rowOrder, int columnOrder, Field field) {
|
|
||||||
return FieldWidget(
|
|
||||||
rowOrder: rowOrder,
|
|
||||||
columnOrder: columnOrder,
|
|
||||||
onIncrease: () => _addToField(field, 1),
|
|
||||||
onDecrease: () => _addToField(field, -1),
|
|
||||||
value: fields[field.index],
|
|
||||||
field: field,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Pet Inventory'),
|
|
||||||
),
|
|
||||||
body: Builder(
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return DefaultTextStyle(
|
|
||||||
style: DefaultTextStyle.of(context).style.copyWith(fontSize: 21.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Semantics(
|
|
||||||
// Since this is the only sort key that the text has, it
|
|
||||||
// will be compared with the 'column' OrdinalSortKeys of all the
|
|
||||||
// fields, because the column sort keys are first in the other fields.
|
|
||||||
//
|
|
||||||
// An ordinal of "0.0" means that it will be traversed before column 1.
|
|
||||||
sortKey: const OrdinalSortKey(0.0),
|
|
||||||
child: const Text(
|
|
||||||
'How many pets do you own?',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Padding(padding: EdgeInsets.symmetric(vertical: 10.0)),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: <Widget>[
|
|
||||||
_makeFieldHeader(1, 0, Field.DOGS),
|
|
||||||
_makeFieldHeader(1, 1, Field.CATS),
|
|
||||||
_makeFieldHeader(1, 2, Field.FISH),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: <Widget>[
|
|
||||||
_makeSpinnerButton(3, 0, Field.DOGS, increment: true),
|
|
||||||
_makeSpinnerButton(3, 1, Field.CATS, increment: true),
|
|
||||||
_makeSpinnerButton(3, 2, Field.FISH, increment: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: <Widget>[
|
|
||||||
_makeEntryField(2, 0, Field.DOGS),
|
|
||||||
_makeEntryField(2, 1, Field.CATS),
|
|
||||||
_makeEntryField(2, 2, Field.FISH),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: <Widget>[
|
|
||||||
_makeSpinnerButton(4, 0, Field.DOGS, increment: false),
|
|
||||||
_makeSpinnerButton(4, 1, Field.CATS, increment: false),
|
|
||||||
_makeSpinnerButton(4, 2, Field.FISH, increment: false),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Padding(padding: EdgeInsets.symmetric(vertical: 10.0)),
|
|
||||||
Semantics(
|
|
||||||
// Since this is the only sort key that the reset button has, it
|
|
||||||
// will be compared with the 'column' OrdinalSortKeys of all the
|
|
||||||
// fields, because the column sort keys are first in the other fields.
|
|
||||||
//
|
|
||||||
// an ordinal of "5.0" means that it will be traversed after column 4.
|
|
||||||
sortKey: const OrdinalSortKey(5.0),
|
|
||||||
child: MaterialButton(
|
|
||||||
child: const Text('RESET'),
|
|
||||||
textTheme: ButtonTextTheme.normal,
|
|
||||||
textColor: Colors.blue,
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
fields = <int>[0, 0, 0];
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(CustomTraversalExample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: CustomTraversalExample
|
|
||||||
|
|
||||||
Summary: An app that demonstrates a custom semantics traversal order.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
This app presents a value selection interface where the fields can be
|
|
||||||
incremented or decremented using spinner arrows. In accessibility mode, the
|
|
||||||
widgets are traversed in a custom order from one column to the next, starting
|
|
||||||
with the column title, moving to the input field, then to the "up" increment
|
|
||||||
button, and lastly to the "down" decrement button.
|
|
||||||
|
|
||||||
When not in accessibility mode, the app works as one would expect.
|
|
||||||
|
|
||||||
Classes: Semantics
|
|
||||||
|
|
||||||
Sample: CustomTraversalExample
|
|
||||||
*/
|
|
@ -1,152 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
/// A [ListTile] containing a dropdown menu that exposes itself as an
|
|
||||||
/// "Adjustable" to screen readers (e.g. TalkBack on Android and VoiceOver on
|
|
||||||
/// iOS).
|
|
||||||
///
|
|
||||||
/// This allows screen reader users to swipe up/down (on iOS) or use the volume
|
|
||||||
/// keys (on Android) to switch between the values in the dropdown menu.
|
|
||||||
/// Depending on what the values in the dropdown menu are this can be a more
|
|
||||||
/// intuitive way of switching values compared to exposing the content of the
|
|
||||||
/// drop down menu as a screen overlay from which the user can select.
|
|
||||||
///
|
|
||||||
/// Users that do not use a screen reader will just see a regular dropdown menu.
|
|
||||||
class AdjustableDropdownListTile extends StatelessWidget {
|
|
||||||
const AdjustableDropdownListTile({
|
|
||||||
this.label,
|
|
||||||
this.value,
|
|
||||||
this.items,
|
|
||||||
this.onChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String label;
|
|
||||||
final String value;
|
|
||||||
final List<String> items;
|
|
||||||
final ValueChanged<String> onChanged;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final int indexOfValue = items.indexOf(value);
|
|
||||||
assert(indexOfValue != -1);
|
|
||||||
|
|
||||||
final bool canIncrease = indexOfValue < items.length - 1;
|
|
||||||
final bool canDecrease = indexOfValue > 0;
|
|
||||||
|
|
||||||
return Semantics(
|
|
||||||
container: true,
|
|
||||||
label: label,
|
|
||||||
value: value,
|
|
||||||
increasedValue: canIncrease ? _increasedValue : null,
|
|
||||||
decreasedValue: canDecrease ? _decreasedValue : null,
|
|
||||||
onIncrease: canIncrease ? _performIncrease : null,
|
|
||||||
onDecrease: canDecrease ? _performDecrease : null,
|
|
||||||
child: ExcludeSemantics(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(label),
|
|
||||||
trailing: DropdownButton<String>(
|
|
||||||
value: value,
|
|
||||||
onChanged: onChanged,
|
|
||||||
items: items.map<DropdownMenuItem<String>>((String item) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: item,
|
|
||||||
child: Text(item),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String get _increasedValue {
|
|
||||||
final int indexOfValue = items.indexOf(value);
|
|
||||||
assert(indexOfValue < items.length - 1);
|
|
||||||
return items[indexOfValue + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
String get _decreasedValue {
|
|
||||||
final int indexOfValue = items.indexOf(value);
|
|
||||||
assert(indexOfValue > 0);
|
|
||||||
return items[indexOfValue - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void _performIncrease() => onChanged(_increasedValue);
|
|
||||||
|
|
||||||
void _performDecrease() => onChanged(_decreasedValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdjustableDropdownExample extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
AdjustableDropdownExampleState createState() => AdjustableDropdownExampleState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdjustableDropdownExampleState extends State<AdjustableDropdownExample> {
|
|
||||||
|
|
||||||
final List<String> items = <String>[
|
|
||||||
'1 second',
|
|
||||||
'5 seconds',
|
|
||||||
'15 seconds',
|
|
||||||
'30 seconds',
|
|
||||||
'1 minute',
|
|
||||||
];
|
|
||||||
String timeout;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Adjustable DropDown'),
|
|
||||||
),
|
|
||||||
body: ListView(
|
|
||||||
children: <Widget>[
|
|
||||||
AdjustableDropdownListTile(
|
|
||||||
label: 'Timeout',
|
|
||||||
value: timeout ?? items[2],
|
|
||||||
items: items,
|
|
||||||
onChanged: (String value) {
|
|
||||||
setState(() {
|
|
||||||
timeout = value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(AdjustableDropdownExample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: AdjustableDropdownListTile
|
|
||||||
|
|
||||||
Summary: A dropdown menu that exposes itself as an "Adjustable" to screen
|
|
||||||
readers.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
This app presents a dropdown menu to the user that exposes itself as an
|
|
||||||
"Adjustable" to screen readers (e.g. TalkBack on Android and VoiceOver on iOS).
|
|
||||||
This allows users of screen readers to cycle through the values of the dropdown
|
|
||||||
menu by swiping up or down on the screen with one finger (on iOS) or by using
|
|
||||||
the volume keys (on Android). Depending on the values in the dropdown this
|
|
||||||
behavior may be more intuitive to screen reader users compared to showing the
|
|
||||||
classical dropdown overlay on screen to choose a value.
|
|
||||||
|
|
||||||
When the screen reader is turned off, the dropdown menu behaves like any
|
|
||||||
dropdown menu would.
|
|
||||||
|
|
||||||
Classes: Semantics
|
|
||||||
|
|
||||||
Sample: AdjustableDropdownListTile
|
|
||||||
|
|
||||||
*/
|
|
@ -1,121 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ExpansionTileSample extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('ExpansionTile'),
|
|
||||||
),
|
|
||||||
body: ListView.builder(
|
|
||||||
itemBuilder: (BuildContext context, int index) => EntryItem(data[index]),
|
|
||||||
itemCount: data.length,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// One entry in the multilevel list displayed by this app.
|
|
||||||
class Entry {
|
|
||||||
Entry(this.title, [this.children = const <Entry>[]]);
|
|
||||||
final String title;
|
|
||||||
final List<Entry> children;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The entire multilevel list displayed by this app.
|
|
||||||
final List<Entry> data = <Entry>[
|
|
||||||
Entry('Chapter A',
|
|
||||||
<Entry>[
|
|
||||||
Entry('Section A0',
|
|
||||||
<Entry>[
|
|
||||||
Entry('Item A0.1'),
|
|
||||||
Entry('Item A0.2'),
|
|
||||||
Entry('Item A0.3'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Entry('Section A1'),
|
|
||||||
Entry('Section A2'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Entry('Chapter B',
|
|
||||||
<Entry>[
|
|
||||||
Entry('Section B0'),
|
|
||||||
Entry('Section B1'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Entry('Chapter C',
|
|
||||||
<Entry>[
|
|
||||||
Entry('Section C0'),
|
|
||||||
Entry('Section C1'),
|
|
||||||
Entry('Section C2',
|
|
||||||
<Entry>[
|
|
||||||
Entry('Item C2.0'),
|
|
||||||
Entry('Item C2.1'),
|
|
||||||
Entry('Item C2.2'),
|
|
||||||
Entry('Item C2.3'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Displays one Entry. If the entry has children then it's displayed
|
|
||||||
// with an ExpansionTile.
|
|
||||||
class EntryItem extends StatelessWidget {
|
|
||||||
const EntryItem(this.entry);
|
|
||||||
|
|
||||||
final Entry entry;
|
|
||||||
|
|
||||||
Widget _buildTiles(Entry root) {
|
|
||||||
if (root.children.isEmpty)
|
|
||||||
return ListTile(title: Text(root.title));
|
|
||||||
return ExpansionTile(
|
|
||||||
key: PageStorageKey<Entry>(root),
|
|
||||||
title: Text(root.title),
|
|
||||||
children: root.children.map<Widget>(_buildTiles).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return _buildTiles(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(ExpansionTileSample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: ExpansionTile
|
|
||||||
|
|
||||||
Summary: An ExpansionTile for building nested lists, with two or more levels.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
This app displays hierarchical data with ExpansionTiles. Tapping a tile
|
|
||||||
expands or collapses the view of its children. When a tile is collapsed
|
|
||||||
its children are disposed so that the widget footprint of the list only
|
|
||||||
reflects what's visible.
|
|
||||||
|
|
||||||
When displayed within a scrollable that creates its list items lazily,
|
|
||||||
like a scrollable list created with `ListView.builder()`, ExpansionTiles
|
|
||||||
can be quite efficient, particularly for material design "expand/collapse"
|
|
||||||
lists.
|
|
||||||
|
|
||||||
|
|
||||||
Classes: ExpansionTile, ListView
|
|
||||||
|
|
||||||
Sample: ExpansionTileSample
|
|
||||||
|
|
||||||
See also:
|
|
||||||
- The "expand/collapse" part of the material design specification:
|
|
||||||
<https://material.io/guidelines/components/lists-controls.html#lists-controls-types-of-list-controls>
|
|
||||||
*/
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(
|
|
||||||
const Center(
|
|
||||||
child: Text(
|
|
||||||
'Instead run:\nflutter run lib/xxx.dart',
|
|
||||||
textDirection: TextDirection.ltr,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class TabbedAppBarSample extends StatelessWidget {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
home: DefaultTabController(
|
|
||||||
length: choices.length,
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Tabbed AppBar'),
|
|
||||||
bottom: TabBar(
|
|
||||||
isScrollable: true,
|
|
||||||
tabs: choices.map<Widget>((Choice choice) {
|
|
||||||
return Tab(
|
|
||||||
text: choice.title,
|
|
||||||
icon: Icon(choice.icon),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: TabBarView(
|
|
||||||
children: choices.map<Widget>((Choice choice) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: ChoiceCard(choice: choice),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Choice {
|
|
||||||
const Choice({ this.title, this.icon });
|
|
||||||
final String title;
|
|
||||||
final IconData icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
const List<Choice> choices = <Choice>[
|
|
||||||
Choice(title: 'CAR', icon: Icons.directions_car),
|
|
||||||
Choice(title: 'BICYCLE', icon: Icons.directions_bike),
|
|
||||||
Choice(title: 'BOAT', icon: Icons.directions_boat),
|
|
||||||
Choice(title: 'BUS', icon: Icons.directions_bus),
|
|
||||||
Choice(title: 'TRAIN', icon: Icons.directions_railway),
|
|
||||||
Choice(title: 'WALK', icon: Icons.directions_walk),
|
|
||||||
];
|
|
||||||
|
|
||||||
class ChoiceCard extends StatelessWidget {
|
|
||||||
const ChoiceCard({ Key key, this.choice }) : super(key: key);
|
|
||||||
|
|
||||||
final Choice choice;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final TextStyle textStyle = Theme.of(context).textTheme.headline4;
|
|
||||||
return Card(
|
|
||||||
color: Colors.white,
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(choice.icon, size: 128.0, color: textStyle.color),
|
|
||||||
Text(choice.title, style: textStyle),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runApp(TabbedAppBarSample());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sample Catalog
|
|
||||||
|
|
||||||
Title: Tabbed AppBar
|
|
||||||
|
|
||||||
Summary: An AppBar with a TabBar for navigating pages just below it.
|
|
||||||
|
|
||||||
Description:
|
|
||||||
A TabBar can be used to navigate among the pages displayed in a TabBarView.
|
|
||||||
Although a TabBar is an ordinary widget that can appear anywhere, it's most often
|
|
||||||
included in the application's AppBar.
|
|
||||||
|
|
||||||
Classes: AppBar, DefaultTabController, TabBar, Scaffold, TabBarView
|
|
||||||
|
|
||||||
Sample: TabbedAppBarSample
|
|
||||||
|
|
||||||
See also:
|
|
||||||
- The "Components-Tabs" section of the material design specification:
|
|
||||||
<https://material.io/go/design-tabs>
|
|
||||||
*/
|
|
@ -1,84 +0,0 @@
|
|||||||
name: sample_catalog
|
|
||||||
description: A collection of Flutter sample apps
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
flutter:
|
|
||||||
sdk: flutter
|
|
||||||
path: 1.8.0-nullsafety.1
|
|
||||||
|
|
||||||
characters: 1.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
collection: 1.15.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
meta: 1.3.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
typed_data: 1.3.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
vector_math: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
|
|
||||||
dev_dependencies:
|
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
flutter_driver:
|
|
||||||
sdk: flutter
|
|
||||||
test: 1.16.0-nullsafety.5
|
|
||||||
|
|
||||||
_fe_analyzer_shared: 7.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
analyzer: 0.39.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
archive: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
args: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
async: 2.5.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
boolean_selector: 2.1.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
charcode: 1.2.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
cli_util: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
clock: 1.1.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
coverage: 0.14.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
crypto: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
csslib: 0.16.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
fake_async: 1.2.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
file: 6.0.0-nullsafety.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
html: 0.14.0+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
http: 0.12.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
http_multi_server: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
http_parser: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
io: 0.3.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
js: 0.6.3-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
json_rpc_2: 2.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
logging: 0.11.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
matcher: 0.12.10-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
mime: 0.9.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
node_interop: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
node_io: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
node_preamble: 1.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
package_config: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
pedantic: 1.10.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
pool: 1.5.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
pub_semver: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
shelf: 0.7.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
shelf_packages_handler: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
shelf_web_socket: 0.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
source_map_stack_trace: 2.1.0-nullsafety.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
source_maps: 0.10.10-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
source_span: 1.8.0-nullsafety.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
stack_trace: 1.10.0-nullsafety.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
stream_channel: 2.1.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
string_scanner: 1.1.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
sync_http: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
term_glyph: 1.2.0-nullsafety.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
test_api: 0.2.19-nullsafety.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
test_core: 0.3.12-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
vm_service: 4.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
watcher: 0.9.7+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
webdriver: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
webkit_inspection_protocol: 0.7.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
yaml: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
|
||||||
|
|
||||||
flutter:
|
|
||||||
uses-material-design: true
|
|
||||||
|
|
||||||
# PUBSPEC CHECKSUM: 5ffe
|
|
@ -1,64 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/animated_list.dart' as animated_list_sample;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('animated_list sample app smoke test', (WidgetTester tester) async {
|
|
||||||
animated_list_sample.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expect(find.text('Item 0'), findsOneWidget);
|
|
||||||
expect(find.text('Item 1'), findsOneWidget);
|
|
||||||
expect(find.text('Item 2'), findsOneWidget);
|
|
||||||
|
|
||||||
final Finder insertButton = find.byTooltip('insert a new item');
|
|
||||||
final Finder removeButton = find.byTooltip('remove the selected item');
|
|
||||||
expect(insertButton, findsOneWidget);
|
|
||||||
expect(removeButton, findsOneWidget);
|
|
||||||
|
|
||||||
// Remove items 0, 1, 2.
|
|
||||||
await tester.tap(find.text('Item 0'));
|
|
||||||
await tester.tap(removeButton);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
await tester.tap(find.text('Item 1'));
|
|
||||||
await tester.tap(removeButton);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
await tester.tap(find.text('Item 2'));
|
|
||||||
await tester.tap(removeButton);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
// Append items 3, 4, 5, 6.
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
expect(find.text('Item 0'), findsNothing);
|
|
||||||
expect(find.text('Item 1'), findsNothing);
|
|
||||||
expect(find.text('Item 2'), findsNothing);
|
|
||||||
expect(find.text('Item 3'), findsOneWidget);
|
|
||||||
expect(find.text('Item 4'), findsOneWidget);
|
|
||||||
expect(find.text('Item 5'), findsOneWidget);
|
|
||||||
expect(find.text('Item 6'), findsOneWidget);
|
|
||||||
|
|
||||||
// Insert items 7, 8 at item 3's position (at the top)
|
|
||||||
await tester.tap(find.text('Item 3'));
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.tap(insertButton);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
expect(find.text('Item 7'), findsOneWidget);
|
|
||||||
expect(find.text('Item 8'), findsOneWidget);
|
|
||||||
|
|
||||||
// Scroll to the end.
|
|
||||||
await tester.fling(find.text('Item 7'), const Offset(0.0, -200.0), 1000.0);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(find.text('Item 6'), findsOneWidget);
|
|
||||||
expect(find.text('Item 8'), findsNothing);
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/app_bar_bottom.dart' as app_bar_bottom_sample;
|
|
||||||
|
|
||||||
final int choiceCount = app_bar_bottom_sample.choices.length;
|
|
||||||
IconData iconAt(int index) => app_bar_bottom_sample.choices[index].icon;
|
|
||||||
|
|
||||||
Finder findChoiceCard(IconData icon) {
|
|
||||||
return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('app_bar_bottom sample smoke test', (WidgetTester tester) async {
|
|
||||||
app_bar_bottom_sample.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Cycle through the choices using the forward and backwards arrows.
|
|
||||||
|
|
||||||
final Finder nextChoice = find.byTooltip('Next choice');
|
|
||||||
for (int i = 0; i < choiceCount; i += 1) {
|
|
||||||
expect(findChoiceCard(iconAt(i)), findsOneWidget);
|
|
||||||
await tester.tap(nextChoice);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
|
|
||||||
final Finder previousChoice = find.byTooltip('Previous choice');
|
|
||||||
for (int i = choiceCount - 1; i >= 0; i -= 1) {
|
|
||||||
expect(findChoiceCard(iconAt(i)), findsOneWidget);
|
|
||||||
await tester.tap(previousChoice);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/basic_app_bar.dart' as basic_app_bar_sample;
|
|
||||||
|
|
||||||
int choiceCount = basic_app_bar_sample.choices.length;
|
|
||||||
IconData iconAt(int index) => basic_app_bar_sample.choices[index].icon;
|
|
||||||
String titleAt(int index) => basic_app_bar_sample.choices[index].title;
|
|
||||||
|
|
||||||
Finder findAppBarIcon(IconData icon) {
|
|
||||||
return find.descendant(of: find.byType(AppBar), matching: find.byIcon(icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
Finder findChoiceCard(IconData icon) {
|
|
||||||
return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('basic_app_bar sample smoke test', (WidgetTester tester) async {
|
|
||||||
basic_app_bar_sample.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Tap on the two action buttons and all of the overflow menu items.
|
|
||||||
// Verify that a Card with the expected icon appears.
|
|
||||||
|
|
||||||
await tester.tap(findAppBarIcon(iconAt(0)));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(findChoiceCard(iconAt(0)), findsOneWidget);
|
|
||||||
|
|
||||||
await tester.tap(findAppBarIcon(iconAt(1)));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(findChoiceCard(iconAt(1)), findsOneWidget);
|
|
||||||
|
|
||||||
for (int i = 2; i < choiceCount; i += 1) {
|
|
||||||
await tester.tap(findAppBarIcon(Icons.more_vert));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
await tester.tap(find.text(titleAt(i)));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(findChoiceCard(iconAt(i)), findsOneWidget);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/custom_semantics.dart' as custom_semantics show main;
|
|
||||||
import 'package:sample_catalog/custom_semantics.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('custom_semantics sample smoke test', (WidgetTester tester) async {
|
|
||||||
// Turn on Semantics
|
|
||||||
final SemanticsHandle semanticsHandler = tester.binding.pipelineOwner.ensureSemantics();
|
|
||||||
final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner;
|
|
||||||
|
|
||||||
// Build the sample app
|
|
||||||
custom_semantics.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify it correctly exposes its semantics.
|
|
||||||
final SemanticsNode semantics = tester.getSemantics(find.byType(AdjustableDropdownListTile));
|
|
||||||
|
|
||||||
expectAdjustable(semantics,
|
|
||||||
hasIncreaseAction: true,
|
|
||||||
hasDecreaseAction: true,
|
|
||||||
label: 'Timeout',
|
|
||||||
decreasedValue: '5 seconds',
|
|
||||||
value: '15 seconds',
|
|
||||||
increasedValue: '30 seconds',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Increase
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.increase);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expectAdjustable(semantics,
|
|
||||||
hasIncreaseAction: true,
|
|
||||||
hasDecreaseAction: true,
|
|
||||||
label: 'Timeout',
|
|
||||||
decreasedValue: '15 seconds',
|
|
||||||
value: '30 seconds',
|
|
||||||
increasedValue: '1 minute',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Increase all the way to highest value
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.increase);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expectAdjustable(semantics,
|
|
||||||
hasIncreaseAction: false,
|
|
||||||
hasDecreaseAction: true,
|
|
||||||
label: 'Timeout',
|
|
||||||
decreasedValue: '30 seconds',
|
|
||||||
value: '1 minute',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Decrease
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.decrease);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expectAdjustable(semantics,
|
|
||||||
hasIncreaseAction: true,
|
|
||||||
hasDecreaseAction: true,
|
|
||||||
label: 'Timeout',
|
|
||||||
decreasedValue: '15 seconds',
|
|
||||||
value: '30 seconds',
|
|
||||||
increasedValue: '1 minute',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Decrease all the way to lowest value
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.decrease);
|
|
||||||
await tester.pump();
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.decrease);
|
|
||||||
await tester.pump();
|
|
||||||
semanticsOwner.performAction(semantics.id, SemanticsAction.decrease);
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
expectAdjustable(semantics,
|
|
||||||
hasIncreaseAction: true,
|
|
||||||
hasDecreaseAction: false,
|
|
||||||
label: 'Timeout',
|
|
||||||
value: '1 second',
|
|
||||||
increasedValue: '5 seconds',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clean-up
|
|
||||||
semanticsHandler.dispose();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void expectAdjustable(
|
|
||||||
SemanticsNode node, {
|
|
||||||
bool hasIncreaseAction = true,
|
|
||||||
bool hasDecreaseAction = true,
|
|
||||||
String label = '',
|
|
||||||
String decreasedValue = '',
|
|
||||||
String value = '',
|
|
||||||
String increasedValue = '',
|
|
||||||
}) {
|
|
||||||
final SemanticsData semanticsData = node.getSemanticsData();
|
|
||||||
|
|
||||||
int actions = 0;
|
|
||||||
if (hasIncreaseAction)
|
|
||||||
actions |= SemanticsAction.increase.index;
|
|
||||||
if (hasDecreaseAction)
|
|
||||||
actions |= SemanticsAction.decrease.index;
|
|
||||||
|
|
||||||
expect(semanticsData.actions, actions);
|
|
||||||
expect(semanticsData.label, label);
|
|
||||||
expect(semanticsData.decreasedValue, decreasedValue);
|
|
||||||
expect(semanticsData.value, value);
|
|
||||||
expect(semanticsData.increasedValue, increasedValue);
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/expansion_tile_sample.dart' as expansion_tile_sample;
|
|
||||||
import 'package:sample_catalog/expansion_tile_sample.dart' show Entry;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('expansion_tile sample smoke test', (WidgetTester tester) async {
|
|
||||||
expansion_tile_sample.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Initially only the top level EntryItems (the "chapters") are present.
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data) {
|
|
||||||
expect(find.text(chapter.title), findsOneWidget);
|
|
||||||
for (final Entry section in chapter.children) {
|
|
||||||
expect(find.text(section.title), findsNothing);
|
|
||||||
for (final Entry item in section.children)
|
|
||||||
expect(find.text(item.title), findsNothing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> scrollUpOneEntry() async {
|
|
||||||
await tester.dragFrom(const Offset(200.0, 200.0), const Offset(0.0, -88.00));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> tapEntry(String title) async {
|
|
||||||
await tester.tap(find.text(title));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand the chapters. Now the chapter and sections, but not the
|
|
||||||
// items, should be present.
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data.reversed)
|
|
||||||
await tapEntry(chapter.title);
|
|
||||||
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data) {
|
|
||||||
expect(find.text(chapter.title), findsOneWidget);
|
|
||||||
for (final Entry section in chapter.children) {
|
|
||||||
expect(find.text(section.title), findsOneWidget);
|
|
||||||
await scrollUpOneEntry();
|
|
||||||
for (final Entry item in section.children)
|
|
||||||
expect(find.text(item.title), findsNothing);
|
|
||||||
}
|
|
||||||
await scrollUpOneEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
// - scroll to the top -
|
|
||||||
await tester.flingFrom(const Offset(200.0, 200.0), const Offset(0.0, 100.0), 5000.0);
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
|
|
||||||
// Expand the sections. Now Widgets for all three levels should be present.
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data) {
|
|
||||||
for (final Entry section in chapter.children) {
|
|
||||||
await tapEntry(section.title);
|
|
||||||
await scrollUpOneEntry();
|
|
||||||
}
|
|
||||||
await scrollUpOneEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're scrolled to the bottom so the very last item is visible.
|
|
||||||
// Working in reverse order, so we don't need to do anymore scrolling,
|
|
||||||
// check that everything is visible and close the sections and
|
|
||||||
// chapters as we go up.
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data.reversed) {
|
|
||||||
expect(find.text(chapter.title), findsOneWidget);
|
|
||||||
for (final Entry section in chapter.children.reversed) {
|
|
||||||
expect(find.text(section.title), findsOneWidget);
|
|
||||||
for (final Entry item in section.children.reversed)
|
|
||||||
expect(find.text(item.title), findsOneWidget);
|
|
||||||
await tapEntry(section.title); // close the section
|
|
||||||
}
|
|
||||||
await tapEntry(chapter.title); // close the chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally only the top level EntryItems (the "chapters") are present.
|
|
||||||
for (final Entry chapter in expansion_tile_sample.data) {
|
|
||||||
expect(find.text(chapter.title), findsOneWidget);
|
|
||||||
for (final Entry section in chapter.children) {
|
|
||||||
expect(find.text(section.title), findsNothing);
|
|
||||||
for (final Entry item in section.children)
|
|
||||||
expect(find.text(item.title), findsNothing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:sample_catalog/tabbed_app_bar.dart' as tabbed_app_bar_sample;
|
|
||||||
|
|
||||||
final int choiceCount = tabbed_app_bar_sample.choices.length;
|
|
||||||
IconData iconAt(int index) => tabbed_app_bar_sample.choices[index].icon;
|
|
||||||
|
|
||||||
Finder findChoiceCard(IconData icon) {
|
|
||||||
return find.descendant(of: find.byType(Card), matching: find.byIcon(icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
Finder findTab(IconData icon) {
|
|
||||||
return find.descendant(of: find.byType(Tab), matching: find.byIcon(icon));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('tabbed_app_bar sample smoke test', (WidgetTester tester) async {
|
|
||||||
tabbed_app_bar_sample.main();
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Tap on each tab, verify that a Card with the expected icon appears.
|
|
||||||
for (int i = 0; i < choiceCount; i += 1) {
|
|
||||||
await tester.tap(findTab(iconAt(i)));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(findChoiceCard(iconAt(i)), findsOneWidget);
|
|
||||||
// Scroll the tabBar by about one tab width
|
|
||||||
await tester.drag(find.byType(TabBar), const Offset(-24.0, 0.0));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
The screenshot.dart and screenshot_test.dart files were generated by ../bin/sample_page.dart. They should not be checked in.
|
|
@ -171,11 +171,6 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
|
|||||||
/// can expand and collapse.
|
/// can expand and collapse.
|
||||||
/// * <https://material.io/design/components/app-bars-top.html>
|
/// * <https://material.io/design/components/app-bars-top.html>
|
||||||
/// * Cookbook: [Place a floating app bar above a list](https://flutter.dev/docs/cookbook/lists/floating-app-bar)
|
/// * Cookbook: [Place a floating app bar above a list](https://flutter.dev/docs/cookbook/lists/floating-app-bar)
|
||||||
/// * See our
|
|
||||||
/// [AppBar Basics sample](https://flutter.dev/docs/catalog/samples/basic-app-bar)
|
|
||||||
/// and our advanced samples with app bars with
|
|
||||||
/// [tabs](https://flutter.dev/docs/catalog/samples/tabbed-app-bar) or
|
|
||||||
/// [custom bottom widgets](https://flutter.dev/docs/catalog/samples/app-bar-bottom).
|
|
||||||
class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
/// Creates a material design app bar.
|
/// Creates a material design app bar.
|
||||||
///
|
///
|
||||||
|
@ -1412,8 +1412,6 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
|
|||||||
/// * [ScaffoldState], which is the state associated with this widget.
|
/// * [ScaffoldState], which is the state associated with this widget.
|
||||||
/// * <https://material.io/design/layout/responsive-layout-grid.html>
|
/// * <https://material.io/design/layout/responsive-layout-grid.html>
|
||||||
/// * Cookbook: [Add a Drawer to a screen](https://flutter.dev/docs/cookbook/design/drawer)
|
/// * Cookbook: [Add a Drawer to a screen](https://flutter.dev/docs/cookbook/design/drawer)
|
||||||
/// * See our
|
|
||||||
/// [Scaffold Sample Apps](https://flutter.dev/docs/catalog/samples/Scaffold).
|
|
||||||
class Scaffold extends StatefulWidget {
|
class Scaffold extends StatefulWidget {
|
||||||
/// Creates a visual scaffold for material design widgets.
|
/// Creates a visual scaffold for material design widgets.
|
||||||
const Scaffold({
|
const Scaffold({
|
||||||
|