Add flutter_lints to form_app (#822)

pull/833/head
Brett Morgan 3 years ago committed by GitHub
parent fc1fe989fb
commit 12ba3b2245
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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"
android {
compileSdkVersion 28
compileSdkVersion 30
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "dev.flutter.formApp.form_app"
minSdkVersion 16
targetSdkVersion 28
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}

@ -1,12 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.flutter.formApp.form_app">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
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:icon="@mipmap/ic_launcher">
<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>

@ -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"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- 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.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
@ -12,7 +12,7 @@
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:color/white</item>
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

@ -6,7 +6,7 @@ buildscript {
}
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"
}
}
@ -21,8 +21,6 @@ allprojects {
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}

@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

@ -3,4 +3,4 @@ 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
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'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")

@ -18,6 +18,7 @@ Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>

@ -272,7 +272,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -289,16 +289,8 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
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 = dev.flutter.formApp.formApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -354,7 +346,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -403,7 +395,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -421,16 +413,8 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
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 = dev.flutter.formApp.formApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -448,16 +432,8 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
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 = dev.flutter.formApp.formApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
location = "self:">
</FileRef>
</Workspace>

@ -15,7 +15,7 @@ import 'src/validation.dart';
final http.Client httpClient = MockClient();
void main() {
runApp(FormApp());
runApp(const FormApp());
}
final demos = [
@ -29,41 +29,44 @@ final demos = [
Demo(
name: 'Autofill',
route: '/autofill',
builder: (context) => AutofillDemo(),
builder: (context) => const AutofillDemo(),
),
Demo(
name: 'Form widgets',
route: '/form_widgets',
builder: (context) => FormWidgetsDemo(),
builder: (context) => const FormWidgetsDemo(),
),
Demo(
name: 'Validation',
route: '/validation',
builder: (context) => FormValidationDemo(),
builder: (context) => const FormValidationDemo(),
),
];
class FormApp extends StatelessWidget {
const FormApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Form Samples',
theme: ThemeData(primarySwatch: Colors.teal),
routes: Map.fromEntries(demos.map((d) => MapEntry(d.route, d.builder))),
home: HomePage(),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Samples'),
title: const Text('Form Samples'),
),
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 {
final Demo demo;
DemoTile(this.demo);
const DemoTile({this.demo, Key key}) : super(key: key);
@override
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:
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart
class AutofillDemo extends StatefulWidget {
const AutofillDemo({Key key}) : super(key: key);
@override
_AutofillDemoState createState() => _AutofillDemoState();
}
@ -18,36 +20,36 @@ class _AutofillDemoState extends State<AutofillDemo> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Autofill'),
title: const Text('Autofill'),
),
body: Form(
key: _formKey,
child: Scrollbar(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: AutofillGroup(
child: Column(
children: [
...[
Text('This sample demonstrates autofill. '),
const Text('This sample demonstrates autofill. '),
TextFormField(
autofocus: true,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
decoration: const InputDecoration(
hintText: 'Jane',
labelText: 'First Name',
),
autofillHints: [AutofillHints.givenName],
autofillHints: const [AutofillHints.givenName],
),
TextFormField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
decoration: const InputDecoration(
hintText: 'Doe',
labelText: 'Last Name',
),
autofillHints: [AutofillHints.familyName],
autofillHints: const [AutofillHints.familyName],
),
TextField(
const TextField(
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
@ -56,7 +58,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
),
autofillHints: [AutofillHints.email],
),
TextField(
const TextField(
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
@ -65,7 +67,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
),
autofillHints: <String>[AutofillHints.telephoneNumber],
),
TextField(
const TextField(
keyboardType: TextInputType.streetAddress,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
@ -74,7 +76,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
),
autofillHints: <String>[AutofillHints.streetAddressLine1],
),
TextField(
const TextField(
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
@ -83,7 +85,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
),
autofillHints: <String>[AutofillHints.postalCode],
),
TextField(
const TextField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
hintText: 'United States',
@ -91,7 +93,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
),
autofillHints: <String>[AutofillHints.countryName],
),
TextField(
const TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: '1',
@ -102,7 +104,7 @@ class _AutofillDemoState extends State<AutofillDemo> {
].expand(
(widget) => [
widget,
SizedBox(
const SizedBox(
height: 24,
)
],

@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
class FormWidgetsDemo extends StatefulWidget {
const FormWidgetsDemo({Key key}) : super(key: key);
@override
_FormWidgetsDemoState createState() => _FormWidgetsDemoState();
}
@ -23,7 +25,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form widgets'),
title: const Text('Form widgets'),
),
body: Form(
key: _formKey,
@ -32,16 +34,16 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
alignment: Alignment.topCenter,
child: Card(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 400),
constraints: const BoxConstraints(maxWidth: 400),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...[
TextFormField(
decoration: InputDecoration(
decoration: const InputDecoration(
filled: true,
hintText: 'Enter a title...',
labelText: 'Title',
@ -53,8 +55,8 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
},
),
TextFormField(
decoration: InputDecoration(
border: const OutlineInputBorder(),
decoration: const InputDecoration(
border: OutlineInputBorder(),
filled: true,
hintText: 'Enter a description...',
labelText: 'Description',
@ -64,7 +66,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
},
maxLines: 5,
),
_FormDatePicker(
_FormDatePicker<DateTime>(
date: date,
onChanged: (value) {
setState(() {
@ -139,7 +141,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
].expand(
(widget) => [
widget,
SizedBox(
const SizedBox(
height: 24,
)
],
@ -156,11 +158,11 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
}
}
class _FormDatePicker extends StatefulWidget {
class _FormDatePicker<T> extends StatefulWidget {
final DateTime date;
final ValueChanged onChanged;
final ValueChanged<T> onChanged;
_FormDatePicker({
const _FormDatePicker({
this.date,
this.onChanged,
});
@ -191,7 +193,7 @@ class _FormDatePickerState extends State<_FormDatePicker> {
],
),
TextButton(
child: Text('Edit'),
child: const Text('Edit'),
onPressed: () async {
var newDate = await showDatePicker(
context: context,

@ -11,10 +11,10 @@ class MockClient extends Mock implements http.Client {
MockClient() {
when(post('https://example.com/signin', body: anyNamed('body')))
.thenAnswer((answering) {
var body = answering.namedArguments[Symbol('body')];
dynamic body = answering.namedArguments[const Symbol('body')];
if (body != null && body is String) {
var decodedJson = json.decode(body);
var decodedJson = json.decode(body) as Map<String, String>;
if (decodedJson['email'] == 'root' &&
decodedJson['password'] == 'password') {

@ -29,9 +29,10 @@ class FormData {
class SignInHttpDemo extends StatefulWidget {
final http.Client httpClient;
SignInHttpDemo({
const SignInHttpDemo({
this.httpClient,
});
Key key,
}) : super(key: key);
@override
_SignInHttpDemoState createState() => _SignInHttpDemoState();
@ -44,19 +45,19 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sign in Form'),
title: const Text('Sign in Form'),
),
body: Form(
child: Scrollbar(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: Column(
children: [
...[
TextFormField(
autofocus: true,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
decoration: const InputDecoration(
filled: true,
hintText: 'Your email address',
labelText: 'Email',
@ -66,7 +67,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
},
),
TextFormField(
decoration: InputDecoration(
decoration: const InputDecoration(
filled: true,
labelText: 'Password',
),
@ -76,7 +77,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
},
),
TextButton(
child: Text('Sign in'),
child: const Text('Sign in'),
onPressed: () async {
// Use a JSON encoded string to send
var result = await widget.httpClient.post(
@ -96,7 +97,7 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
].expand(
(widget) => [
widget,
SizedBox(
const SizedBox(
height: 24,
)
],
@ -110,13 +111,13 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
}
void _showDialog(String message) {
showDialog(
showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: Text(message),
actions: [
TextButton(
child: Text('OK'),
child: const Text('OK'),
onPressed: () => Navigator.of(context).pop(),
),
],

@ -6,6 +6,8 @@ import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart' as english_words;
class FormValidationDemo extends StatefulWidget {
const FormValidationDemo({Key key}) : super(key: key);
@override
_FormValidationDemoState createState() => _FormValidationDemoState();
}
@ -20,13 +22,13 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('📖 Story Generator'),
title: const Text('📖 Story Generator'),
actions: [
Padding(
padding: EdgeInsets.all(8),
padding: const EdgeInsets.all(8),
child: TextButton(
style: TextButton.styleFrom(primary: Colors.white),
child: Text('Submit'),
child: const Text('Submit'),
onPressed: () {
// Validate the form by getting the FormState from the GlobalKey
// and calling validate() on it.
@ -35,14 +37,14 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
return;
}
showDialog(
showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: Text('Your story'),
title: const Text('Your story'),
content: Text('The $adjective developer saw a $noun'),
actions: [
TextButton(
child: Text('Done'),
child: const Text('Done'),
onPressed: () {
Navigator.of(context).pop();
},
@ -59,7 +61,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
key: _formKey,
child: Scrollbar(
child: SingleChildScrollView(
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
child: Column(
children: [
// 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.';
},
decoration: InputDecoration(
decoration: const InputDecoration(
filled: true,
hintText: 'e.g. quick, beautiful, interesting',
labelText: 'Enter an adjective',
@ -84,7 +86,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
adjective = value;
},
),
SizedBox(
const SizedBox(
height: 24,
),
// 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.';
},
decoration: InputDecoration(
decoration: const InputDecoration(
filled: true,
hintText: 'i.e. a person, place or thing',
labelText: 'Enter a noun',
@ -107,12 +109,12 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
noun = value;
},
),
SizedBox(
const SizedBox(
height: 24,
),
// A custom form field that requires the user to check a
// checkbox.
FormField(
FormField<bool>(
initialValue: false,
validator: (value) {
if (value == false) {
@ -120,7 +122,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
}
return null;
},
builder: (FormFieldState formFieldState) {
builder: (formFieldState) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

@ -202,6 +202,13 @@ packages:
description: flutter
source: sdk
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:
dependency: "direct dev"
description: flutter
@ -277,6 +284,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.1"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logging:
dependency: transitive
description:

@ -1,6 +1,6 @@
name: form_app
description: A sample demonstrating different types of forms and best practices
publish_to: 'none'
publish_to: "none"
version: 1.0.0+1
environment:
@ -21,5 +21,7 @@ dev_dependencies:
sdk: flutter
json_serializable: ^3.0.0
build_runner: ^1.10.0
flutter_lints: ^1.0.0
flutter:
uses-material-design: true

@ -1,6 +1,19 @@
<!DOCTYPE html>
<html>
<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 content="IE=Edge" http-equiv="X-UA-Compatible">
<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">
<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>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<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) {
// Service workers are supported. Use them.
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 src="main.dart.js" type="application/javascript"></script>
</body>
</html>
Loading…
Cancel
Save