mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Add flutter_lints to form_app (#822)
This commit is contained in:
19
form_app/analysis_options.yaml
Normal file
19
form_app/analysis_options.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
||||||
|
implicit-dynamic: false
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
avoid_types_on_closure_parameters: true
|
||||||
|
avoid_void_async: true
|
||||||
|
cancel_subscriptions: true
|
||||||
|
close_sinks: true
|
||||||
|
directives_ordering: true
|
||||||
|
package_api_docs: true
|
||||||
|
package_prefixed_library_names: true
|
||||||
|
test_types_in_equals: true
|
||||||
|
throw_in_finally: true
|
||||||
|
unnecessary_statements: true
|
||||||
@@ -26,21 +26,17 @@ apply plugin: 'kotlin-android'
|
|||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 30
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
disable 'InvalidPackage'
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "dev.flutter.formApp.form_app"
|
applicationId "dev.flutter.formApp.form_app"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 28
|
targetSdkVersion 30
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="dev.flutter.formApp.form_app">
|
package="dev.flutter.formApp.form_app">
|
||||||
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
<application
|
||||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
|
||||||
In most cases you can leave this as-is, but you if you want to provide
|
|
||||||
additional functionality it is fine to subclass or reimplement
|
|
||||||
FlutterApplication and put your custom class here. -->
|
|
||||||
<application
|
|
||||||
android:name="io.flutter.app.FlutterApplication"
|
|
||||||
android:label="form_app"
|
android:label="form_app"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
18
form_app/android/app/src/main/res/values-night/styles.xml
Normal file
18
form_app/android/app/src/main/res/values-night/styles.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Theme applied to the Android Window while the process is starting -->
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
Flutter draws its first frame -->
|
Flutter draws its first frame -->
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
running.
|
running.
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">@android:color/white</item>
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,6 @@ allprojects {
|
|||||||
rootProject.buildDir = '../build'
|
rootProject.buildDir = '../build'
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
}
|
|
||||||
subprojects {
|
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
android.enableR8=true
|
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
// 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'
|
include ':app'
|
||||||
|
|
||||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||||
|
|||||||
1
form_app/ios/.gitignore
vendored
1
form_app/ios/.gitignore
vendored
@@ -18,6 +18,7 @@ Flutter/App.framework
|
|||||||
Flutter/Flutter.framework
|
Flutter/Flutter.framework
|
||||||
Flutter/Flutter.podspec
|
Flutter/Flutter.podspec
|
||||||
Flutter/Generated.xcconfig
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
Flutter/app.flx
|
Flutter/app.flx
|
||||||
Flutter/app.zip
|
Flutter/app.zip
|
||||||
Flutter/flutter_assets/
|
Flutter/flutter_assets/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>en</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>App</string>
|
<string>App</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|||||||
@@ -272,7 +272,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@@ -289,16 +289,8 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -354,7 +346,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@@ -403,7 +395,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@@ -421,16 +413,8 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -448,16 +432,8 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.formApp.formApp;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "self:">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import 'src/validation.dart';
|
|||||||
final http.Client httpClient = MockClient();
|
final http.Client httpClient = MockClient();
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(FormApp());
|
runApp(const FormApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
final demos = [
|
final demos = [
|
||||||
@@ -29,41 +29,44 @@ final demos = [
|
|||||||
Demo(
|
Demo(
|
||||||
name: 'Autofill',
|
name: 'Autofill',
|
||||||
route: '/autofill',
|
route: '/autofill',
|
||||||
builder: (context) => AutofillDemo(),
|
builder: (context) => const AutofillDemo(),
|
||||||
),
|
),
|
||||||
Demo(
|
Demo(
|
||||||
name: 'Form widgets',
|
name: 'Form widgets',
|
||||||
route: '/form_widgets',
|
route: '/form_widgets',
|
||||||
builder: (context) => FormWidgetsDemo(),
|
builder: (context) => const FormWidgetsDemo(),
|
||||||
),
|
),
|
||||||
Demo(
|
Demo(
|
||||||
name: 'Validation',
|
name: 'Validation',
|
||||||
route: '/validation',
|
route: '/validation',
|
||||||
builder: (context) => FormValidationDemo(),
|
builder: (context) => const FormValidationDemo(),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
class FormApp extends StatelessWidget {
|
class FormApp extends StatelessWidget {
|
||||||
|
const FormApp({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Form Samples',
|
title: 'Form Samples',
|
||||||
theme: ThemeData(primarySwatch: Colors.teal),
|
theme: ThemeData(primarySwatch: Colors.teal),
|
||||||
routes: Map.fromEntries(demos.map((d) => MapEntry(d.route, d.builder))),
|
routes: Map.fromEntries(demos.map((d) => MapEntry(d.route, d.builder))),
|
||||||
home: HomePage(),
|
home: const HomePage(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomePage extends StatelessWidget {
|
class HomePage extends StatelessWidget {
|
||||||
|
const HomePage({Key key}) : super(key: key);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Form Samples'),
|
title: const Text('Form Samples'),
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [...demos.map((d) => DemoTile(d))],
|
children: [...demos.map((d) => DemoTile(demo: d))],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -72,7 +75,7 @@ class HomePage extends StatelessWidget {
|
|||||||
class DemoTile extends StatelessWidget {
|
class DemoTile extends StatelessWidget {
|
||||||
final Demo demo;
|
final Demo demo;
|
||||||
|
|
||||||
DemoTile(this.demo);
|
const DemoTile({this.demo, Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import 'package:flutter/material.dart';
|
|||||||
// Demonstrates how to use autofill hints. The full list of hints is here:
|
// Demonstrates how to use autofill hints. The full list of hints is here:
|
||||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart
|
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart
|
||||||
class AutofillDemo extends StatefulWidget {
|
class AutofillDemo extends StatefulWidget {
|
||||||
|
const AutofillDemo({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AutofillDemoState createState() => _AutofillDemoState();
|
_AutofillDemoState createState() => _AutofillDemoState();
|
||||||
}
|
}
|
||||||
@@ -18,36 +20,36 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Autofill'),
|
title: const Text('Autofill'),
|
||||||
),
|
),
|
||||||
body: Form(
|
body: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: AutofillGroup(
|
child: AutofillGroup(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
...[
|
...[
|
||||||
Text('This sample demonstrates autofill. '),
|
const Text('This sample demonstrates autofill. '),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Jane',
|
hintText: 'Jane',
|
||||||
labelText: 'First Name',
|
labelText: 'First Name',
|
||||||
),
|
),
|
||||||
autofillHints: [AutofillHints.givenName],
|
autofillHints: const [AutofillHints.givenName],
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Doe',
|
hintText: 'Doe',
|
||||||
labelText: 'Last Name',
|
labelText: 'Last Name',
|
||||||
),
|
),
|
||||||
autofillHints: [AutofillHints.familyName],
|
autofillHints: const [AutofillHints.familyName],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -56,7 +58,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
),
|
),
|
||||||
autofillHints: [AutofillHints.email],
|
autofillHints: [AutofillHints.email],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -65,7 +67,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
),
|
),
|
||||||
autofillHints: <String>[AutofillHints.telephoneNumber],
|
autofillHints: <String>[AutofillHints.telephoneNumber],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
keyboardType: TextInputType.streetAddress,
|
keyboardType: TextInputType.streetAddress,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -74,7 +76,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
),
|
),
|
||||||
autofillHints: <String>[AutofillHints.streetAddressLine1],
|
autofillHints: <String>[AutofillHints.streetAddressLine1],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -83,7 +85,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
),
|
),
|
||||||
autofillHints: <String>[AutofillHints.postalCode],
|
autofillHints: <String>[AutofillHints.postalCode],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'United States',
|
hintText: 'United States',
|
||||||
@@ -91,7 +93,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
),
|
),
|
||||||
autofillHints: <String>[AutofillHints.countryName],
|
autofillHints: <String>[AutofillHints.countryName],
|
||||||
),
|
),
|
||||||
TextField(
|
const TextField(
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: '1',
|
hintText: '1',
|
||||||
@@ -102,7 +104,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
|
|||||||
].expand(
|
].expand(
|
||||||
(widget) => [
|
(widget) => [
|
||||||
widget,
|
widget,
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:intl/intl.dart' as intl;
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
|
||||||
class FormWidgetsDemo extends StatefulWidget {
|
class FormWidgetsDemo extends StatefulWidget {
|
||||||
|
const FormWidgetsDemo({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_FormWidgetsDemoState createState() => _FormWidgetsDemoState();
|
_FormWidgetsDemoState createState() => _FormWidgetsDemoState();
|
||||||
}
|
}
|
||||||
@@ -23,7 +25,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Form widgets'),
|
title: const Text('Form widgets'),
|
||||||
),
|
),
|
||||||
body: Form(
|
body: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
@@ -32,16 +34,16 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: Card(
|
child: Card(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: 400),
|
constraints: const BoxConstraints(maxWidth: 400),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
...[
|
...[
|
||||||
TextFormField(
|
TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'Enter a title...',
|
hintText: 'Enter a title...',
|
||||||
labelText: 'Title',
|
labelText: 'Title',
|
||||||
@@ -53,8 +55,8 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
border: const OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'Enter a description...',
|
hintText: 'Enter a description...',
|
||||||
labelText: 'Description',
|
labelText: 'Description',
|
||||||
@@ -64,7 +66,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
},
|
},
|
||||||
maxLines: 5,
|
maxLines: 5,
|
||||||
),
|
),
|
||||||
_FormDatePicker(
|
_FormDatePicker<DateTime>(
|
||||||
date: date,
|
date: date,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -139,7 +141,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
].expand(
|
].expand(
|
||||||
(widget) => [
|
(widget) => [
|
||||||
widget,
|
widget,
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -156,11 +158,11 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FormDatePicker extends StatefulWidget {
|
class _FormDatePicker<T> extends StatefulWidget {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final ValueChanged onChanged;
|
final ValueChanged<T> onChanged;
|
||||||
|
|
||||||
_FormDatePicker({
|
const _FormDatePicker({
|
||||||
this.date,
|
this.date,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
});
|
});
|
||||||
@@ -191,7 +193,7 @@ class _FormDatePickerState extends State<_FormDatePicker> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('Edit'),
|
child: const Text('Edit'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var newDate = await showDatePicker(
|
var newDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ class MockClient extends Mock implements http.Client {
|
|||||||
MockClient() {
|
MockClient() {
|
||||||
when(post('https://example.com/signin', body: anyNamed('body')))
|
when(post('https://example.com/signin', body: anyNamed('body')))
|
||||||
.thenAnswer((answering) {
|
.thenAnswer((answering) {
|
||||||
var body = answering.namedArguments[Symbol('body')];
|
dynamic body = answering.namedArguments[const Symbol('body')];
|
||||||
|
|
||||||
if (body != null && body is String) {
|
if (body != null && body is String) {
|
||||||
var decodedJson = json.decode(body);
|
var decodedJson = json.decode(body) as Map<String, String>;
|
||||||
|
|
||||||
if (decodedJson['email'] == 'root' &&
|
if (decodedJson['email'] == 'root' &&
|
||||||
decodedJson['password'] == 'password') {
|
decodedJson['password'] == 'password') {
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ class FormData {
|
|||||||
class SignInHttpDemo extends StatefulWidget {
|
class SignInHttpDemo extends StatefulWidget {
|
||||||
final http.Client httpClient;
|
final http.Client httpClient;
|
||||||
|
|
||||||
SignInHttpDemo({
|
const SignInHttpDemo({
|
||||||
this.httpClient,
|
this.httpClient,
|
||||||
});
|
Key key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SignInHttpDemoState createState() => _SignInHttpDemoState();
|
_SignInHttpDemoState createState() => _SignInHttpDemoState();
|
||||||
@@ -44,19 +45,19 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Sign in Form'),
|
title: const Text('Sign in Form'),
|
||||||
),
|
),
|
||||||
body: Form(
|
body: Form(
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
...[
|
...[
|
||||||
TextFormField(
|
TextFormField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'Your email address',
|
hintText: 'Your email address',
|
||||||
labelText: 'Email',
|
labelText: 'Email',
|
||||||
@@ -66,7 +67,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
labelText: 'Password',
|
labelText: 'Password',
|
||||||
),
|
),
|
||||||
@@ -76,7 +77,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('Sign in'),
|
child: const Text('Sign in'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// Use a JSON encoded string to send
|
// Use a JSON encoded string to send
|
||||||
var result = await widget.httpClient.post(
|
var result = await widget.httpClient.post(
|
||||||
@@ -96,7 +97,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
|||||||
].expand(
|
].expand(
|
||||||
(widget) => [
|
(widget) => [
|
||||||
widget,
|
widget,
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -110,13 +111,13 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showDialog(String message) {
|
void _showDialog(String message) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: Text(message),
|
title: Text(message),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('OK'),
|
child: const Text('OK'),
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:english_words/english_words.dart' as english_words;
|
import 'package:english_words/english_words.dart' as english_words;
|
||||||
|
|
||||||
class FormValidationDemo extends StatefulWidget {
|
class FormValidationDemo extends StatefulWidget {
|
||||||
|
const FormValidationDemo({Key key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_FormValidationDemoState createState() => _FormValidationDemoState();
|
_FormValidationDemoState createState() => _FormValidationDemoState();
|
||||||
}
|
}
|
||||||
@@ -20,13 +22,13 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('📖 Story Generator'),
|
title: const Text('📖 Story Generator'),
|
||||||
actions: [
|
actions: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
style: TextButton.styleFrom(primary: Colors.white),
|
style: TextButton.styleFrom(primary: Colors.white),
|
||||||
child: Text('Submit'),
|
child: const Text('Submit'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Validate the form by getting the FormState from the GlobalKey
|
// Validate the form by getting the FormState from the GlobalKey
|
||||||
// and calling validate() on it.
|
// and calling validate() on it.
|
||||||
@@ -35,14 +37,14 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: Text('Your story'),
|
title: const Text('Your story'),
|
||||||
content: Text('The $adjective developer saw a $noun'),
|
content: Text('The $adjective developer saw a $noun'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('Done'),
|
child: const Text('Done'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
@@ -59,7 +61,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// A text field that validates that the text is an adjective.
|
// A text field that validates that the text is an adjective.
|
||||||
@@ -75,7 +77,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
}
|
}
|
||||||
return 'Not a valid adjective.';
|
return 'Not a valid adjective.';
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'e.g. quick, beautiful, interesting',
|
hintText: 'e.g. quick, beautiful, interesting',
|
||||||
labelText: 'Enter an adjective',
|
labelText: 'Enter an adjective',
|
||||||
@@ -84,7 +86,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
adjective = value;
|
adjective = value;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
// A text field that validates that the text is a noun.
|
// A text field that validates that the text is a noun.
|
||||||
@@ -98,7 +100,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
}
|
}
|
||||||
return 'Not a valid noun.';
|
return 'Not a valid noun.';
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'i.e. a person, place or thing',
|
hintText: 'i.e. a person, place or thing',
|
||||||
labelText: 'Enter a noun',
|
labelText: 'Enter a noun',
|
||||||
@@ -107,12 +109,12 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
noun = value;
|
noun = value;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
// A custom form field that requires the user to check a
|
// A custom form field that requires the user to check a
|
||||||
// checkbox.
|
// checkbox.
|
||||||
FormField(
|
FormField<bool>(
|
||||||
initialValue: false,
|
initialValue: false,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == false) {
|
if (value == false) {
|
||||||
@@ -120,7 +122,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
builder: (FormFieldState formFieldState) {
|
builder: (formFieldState) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -202,6 +202,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_lints
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -277,6 +284,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.1"
|
version: "3.5.1"
|
||||||
|
lints:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: form_app
|
name: form_app
|
||||||
description: A sample demonstrating different types of forms and best practices
|
description: A sample demonstrating different types of forms and best practices
|
||||||
publish_to: 'none'
|
publish_to: "none"
|
||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@@ -21,5 +21,7 @@ dev_dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
json_serializable: ^3.0.0
|
json_serializable: ^3.0.0
|
||||||
build_runner: ^1.10.0
|
build_runner: ^1.10.0
|
||||||
|
flutter_lints: ^1.0.0
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
-->
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
<meta name="description" content="A sample demonstrating different types of forms and best practices">
|
<meta name="description" content="A sample demonstrating different types of forms and best practices">
|
||||||
@@ -11,23 +24,78 @@
|
|||||||
<meta name="apple-mobile-web-app-title" content="form_app">
|
<meta name="apple-mobile-web-app-title" content="form_app">
|
||||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
<!-- Favicon -->
|
|
||||||
<link rel="shortcut icon" type="image/png" href="favicon.png"/>
|
|
||||||
|
|
||||||
<title>form_app</title>
|
<title>form_app</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||||
application. For more information, see:
|
application. For more information, see:
|
||||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||||
<script>
|
<script>
|
||||||
|
var serviceWorkerVersion = null;
|
||||||
|
var scriptLoaded = false;
|
||||||
|
function loadMainDartJs() {
|
||||||
|
if (scriptLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scriptLoaded = true;
|
||||||
|
var scriptTag = document.createElement('script');
|
||||||
|
scriptTag.src = 'main.dart.js';
|
||||||
|
scriptTag.type = 'application/javascript';
|
||||||
|
document.body.append(scriptTag);
|
||||||
|
}
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
|
// Service workers are supported. Use them.
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
navigator.serviceWorker.register('flutter_service_worker.js');
|
// Wait for registration to finish before dropping the <script> tag.
|
||||||
|
// Otherwise, the browser will load the script multiple times,
|
||||||
|
// potentially different versions.
|
||||||
|
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||||
|
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||||
|
.then((reg) => {
|
||||||
|
function waitForActivation(serviceWorker) {
|
||||||
|
serviceWorker.addEventListener('statechange', () => {
|
||||||
|
if (serviceWorker.state == 'activated') {
|
||||||
|
console.log('Installed new service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||||
|
// No active web worker and we have installed or are installing
|
||||||
|
// one for the first time. Simply wait for it to activate.
|
||||||
|
waitForActivation(reg.installing ?? reg.waiting);
|
||||||
|
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||||
|
// When the app updates the serviceWorkerVersion changes, so we
|
||||||
|
// need to ask the service worker to update.
|
||||||
|
console.log('New service worker available.');
|
||||||
|
reg.update();
|
||||||
|
waitForActivation(reg.installing);
|
||||||
|
} else {
|
||||||
|
// Existing service worker is still good.
|
||||||
|
console.log('Loading app from service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If service worker doesn't succeed in a reasonable amount of time,
|
||||||
|
// fallback to plaint <script> tag.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!scriptLoaded) {
|
||||||
|
console.warn(
|
||||||
|
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||||
|
);
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
}, 4000);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Service workers not supported. Just drop the <script> tag.
|
||||||
|
loadMainDartJs();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="main.dart.js" type="application/javascript"></script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user