-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
115,118 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
5d013b40a6e9424f61a9384b8fd38fa9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}] |
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// 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 script installs service_worker.js to provide PWA functionality to | ||
* application. For more information, see: | ||
* https://developers.google.com/web/fundamentals/primers/service-workers | ||
*/ | ||
|
||
if (!_flutter) { | ||
var _flutter = {}; | ||
} | ||
_flutter.loader = null; | ||
|
||
(function() { | ||
"use strict"; | ||
class FlutterLoader { | ||
/** | ||
* Creates a FlutterLoader, and initializes its instance methods. | ||
*/ | ||
constructor() { | ||
// TODO: Move the below methods to "#private" once supported by all the browsers | ||
// we support. In the meantime, we use the "revealing module" pattern. | ||
|
||
// Watchdog to prevent injecting the main entrypoint multiple times. | ||
this._scriptLoaded = null; | ||
|
||
// Resolver for the pending promise returned by loadEntrypoint. | ||
this._didCreateEngineInitializerResolve = null; | ||
|
||
// Called by Flutter web. | ||
// Bound to `this` now, so "this" is preserved across JS <-> Flutter jumps. | ||
this.didCreateEngineInitializer = this._didCreateEngineInitializer.bind(this); | ||
} | ||
|
||
/** | ||
* Initializes the main.dart.js with/without serviceWorker. | ||
* @param {*} options | ||
* @returns a Promise that will eventually resolve with an EngineInitializer, | ||
* or will be rejected with the error caused by the loader. | ||
*/ | ||
loadEntrypoint(options) { | ||
const { | ||
entrypointUrl = "main.dart.js", | ||
serviceWorker, | ||
} = (options || {}); | ||
return this._loadWithServiceWorker(entrypointUrl, serviceWorker); | ||
} | ||
|
||
/** | ||
* Resolves the promise created by loadEntrypoint. | ||
* Called by Flutter through the public `didCreateEngineInitializer` method, | ||
* which is bound to the correct instance of the FlutterLoader on the page. | ||
* @param {*} engineInitializer | ||
*/ | ||
_didCreateEngineInitializer(engineInitializer) { | ||
if (typeof this._didCreateEngineInitializerResolve != "function") { | ||
console.warn("Do not call didCreateEngineInitializer by hand. Start with loadEntrypoint instead."); | ||
} | ||
this._didCreateEngineInitializerResolve(engineInitializer); | ||
// Remove the public method after it's done, so Flutter Web can hot restart. | ||
delete this.didCreateEngineInitializer; | ||
} | ||
|
||
_loadEntrypoint(entrypointUrl) { | ||
if (!this._scriptLoaded) { | ||
console.debug("Injecting <script> tag."); | ||
this._scriptLoaded = new Promise((resolve, reject) => { | ||
let scriptTag = document.createElement("script"); | ||
scriptTag.src = entrypointUrl; | ||
scriptTag.type = "application/javascript"; | ||
// Cache the resolve, so it can be called from Flutter. | ||
// Note: Flutter hot restart doesn't re-create this promise, so this | ||
// can only be called once. Instead, we need to model this as a stream | ||
// of `engineCreated` events coming from Flutter that are handled by JS. | ||
this._didCreateEngineInitializerResolve = resolve; | ||
scriptTag.addEventListener("error", reject); | ||
document.body.append(scriptTag); | ||
}); | ||
} | ||
|
||
return this._scriptLoaded; | ||
} | ||
|
||
_waitForServiceWorkerActivation(serviceWorker, entrypointUrl) { | ||
if (!serviceWorker || serviceWorker.state == "activated") { | ||
if (!serviceWorker) { | ||
console.warn("Cannot activate a null service worker."); | ||
} else { | ||
console.debug("Service worker already active."); | ||
} | ||
return this._loadEntrypoint(entrypointUrl); | ||
} | ||
return new Promise((resolve, _) => { | ||
serviceWorker.addEventListener("statechange", () => { | ||
if (serviceWorker.state == "activated") { | ||
console.debug("Installed new service worker."); | ||
resolve(this._loadEntrypoint(entrypointUrl)); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
_loadWithServiceWorker(entrypointUrl, serviceWorkerOptions) { | ||
if (!("serviceWorker" in navigator) || serviceWorkerOptions == null) { | ||
console.warn("Service worker not supported (or configured).", serviceWorkerOptions); | ||
return this._loadEntrypoint(entrypointUrl); | ||
} | ||
|
||
const { | ||
serviceWorkerVersion, | ||
timeoutMillis = 4000, | ||
} = serviceWorkerOptions; | ||
|
||
let serviceWorkerUrl = "flutter_service_worker.js?v=" + serviceWorkerVersion; | ||
let loader = navigator.serviceWorker.register(serviceWorkerUrl) | ||
.then((reg) => { | ||
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. | ||
let sw = reg.installing || reg.waiting; | ||
return this._waitForServiceWorkerActivation(sw, entrypointUrl); | ||
} 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.debug("New service worker available."); | ||
return reg.update().then((reg) => { | ||
console.debug("Service worker updated."); | ||
let sw = reg.installing || reg.waiting || reg.active; | ||
return this._waitForServiceWorkerActivation(sw, entrypointUrl); | ||
}); | ||
} else { | ||
// Existing service worker is still good. | ||
console.debug("Loading app from service worker."); | ||
return this._loadEntrypoint(entrypointUrl); | ||
} | ||
}) | ||
.catch((error) => { | ||
// Some exception happened while registering/activating the service worker. | ||
console.warn("Failed to register or activate service worker:", error); | ||
return this._loadEntrypoint(entrypointUrl); | ||
}); | ||
|
||
// Timeout race promise | ||
let timeout; | ||
if (timeoutMillis > 0) { | ||
timeout = new Promise((resolve, _) => { | ||
setTimeout(() => { | ||
if (!this._scriptLoaded) { | ||
console.warn("Loading from service worker timed out after", timeoutMillis, "milliseconds."); | ||
resolve(this._loadEntrypoint(entrypointUrl)); | ||
} | ||
}, timeoutMillis); | ||
}); | ||
} | ||
|
||
return Promise.race([loader, timeout]); | ||
} | ||
} | ||
|
||
_flutter.loader = new FlutterLoader(); | ||
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
'use strict'; | ||
const MANIFEST = 'flutter-app-manifest'; | ||
const TEMP = 'flutter-temp-cache'; | ||
const CACHE_NAME = 'flutter-app-cache'; | ||
const RESOURCES = { | ||
"favicon.png": "2505b85bce9c67f43272e2675c991828", | ||
"flutter.js": "f85e6fb278b0fd20c349186fb46ae36d", | ||
"canvaskit/profiling/canvaskit.js": "dfb57a8542220c772374503baaf2632c", | ||
"canvaskit/profiling/canvaskit.wasm": "2c16ab2af3d4fbad52da379264e260e8", | ||
"canvaskit/canvaskit.js": "9d49083c3442cfc15366562eb578b5f3", | ||
"canvaskit/canvaskit.wasm": "e58017ff67dd1419dbd7b720458fb1af", | ||
"assets/packages/cupertino_icons/assets/CupertinoIcons.ttf": "6d342eb68f170c97609e9da345464e5e", | ||
"assets/AssetManifest.json": "2efbb41d7877d10aac9d091f58ccd7b9", | ||
"assets/NOTICES": "4f3bc626998488ce3fff3b254fc570d8", | ||
"assets/shaders/ink_sparkle.frag": "c0daf9e25f7dd1c5464a6c6c87f6ab38", | ||
"assets/FontManifest.json": "dc3d03800ccca4601324923c0b1d6d57", | ||
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b", | ||
"main.dart.js": "2c7e751e26693839534d6f58148b6988", | ||
"version.json": "d8cab88cea3fc673e0e62be68ca4daf8", | ||
"index.html": "fc9d22df9b9f3d9e5a8c2a0e7e3960e4", | ||
"/": "fc9d22df9b9f3d9e5a8c2a0e7e3960e4", | ||
"manifest.json": "4771f5b670fc16f20ca34a9b0a191dc1", | ||
"icons/Icon-192.png": "377e72f5465ea739450bf9362c91d8cb", | ||
"icons/Icon-maskable-512.png": "827718ce5d44e2d71d6763abe38fe57a", | ||
"icons/Icon-maskable-192.png": "4bbc1f467501eb77c283e5fa09bf1fee", | ||
"icons/Icon-512.png": "1cf3a4a39fbf4db7ae8946e4f262ae33" | ||
}; | ||
|
||
// The application shell files that are downloaded before a service worker can | ||
// start. | ||
const CORE = [ | ||
"main.dart.js", | ||
"index.html", | ||
"assets/AssetManifest.json", | ||
"assets/FontManifest.json"]; | ||
// During install, the TEMP cache is populated with the application shell files. | ||
self.addEventListener("install", (event) => { | ||
self.skipWaiting(); | ||
return event.waitUntil( | ||
caches.open(TEMP).then((cache) => { | ||
return cache.addAll( | ||
CORE.map((value) => new Request(value, {'cache': 'reload'}))); | ||
}) | ||
); | ||
}); | ||
|
||
// During activate, the cache is populated with the temp files downloaded in | ||
// install. If this service worker is upgrading from one with a saved | ||
// MANIFEST, then use this to retain unchanged resource files. | ||
self.addEventListener("activate", function(event) { | ||
return event.waitUntil(async function() { | ||
try { | ||
var contentCache = await caches.open(CACHE_NAME); | ||
var tempCache = await caches.open(TEMP); | ||
var manifestCache = await caches.open(MANIFEST); | ||
var manifest = await manifestCache.match('manifest'); | ||
// When there is no prior manifest, clear the entire cache. | ||
if (!manifest) { | ||
await caches.delete(CACHE_NAME); | ||
contentCache = await caches.open(CACHE_NAME); | ||
for (var request of await tempCache.keys()) { | ||
var response = await tempCache.match(request); | ||
await contentCache.put(request, response); | ||
} | ||
await caches.delete(TEMP); | ||
// Save the manifest to make future upgrades efficient. | ||
await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES))); | ||
return; | ||
} | ||
var oldManifest = await manifest.json(); | ||
var origin = self.location.origin; | ||
for (var request of await contentCache.keys()) { | ||
var key = request.url.substring(origin.length + 1); | ||
if (key == "") { | ||
key = "/"; | ||
} | ||
// If a resource from the old manifest is not in the new cache, or if | ||
// the MD5 sum has changed, delete it. Otherwise the resource is left | ||
// in the cache and can be reused by the new service worker. | ||
if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) { | ||
await contentCache.delete(request); | ||
} | ||
} | ||
// Populate the cache with the app shell TEMP files, potentially overwriting | ||
// cache files preserved above. | ||
for (var request of await tempCache.keys()) { | ||
var response = await tempCache.match(request); | ||
await contentCache.put(request, response); | ||
} | ||
await caches.delete(TEMP); | ||
// Save the manifest to make future upgrades efficient. | ||
await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES))); | ||
return; | ||
} catch (err) { | ||
// On an unhandled exception the state of the cache cannot be guaranteed. | ||
console.error('Failed to upgrade service worker: ' + err); | ||
await caches.delete(CACHE_NAME); | ||
await caches.delete(TEMP); | ||
await caches.delete(MANIFEST); | ||
} | ||
}()); | ||
}); | ||
|
||
// The fetch handler redirects requests for RESOURCE files to the service | ||
// worker cache. | ||
self.addEventListener("fetch", (event) => { | ||
if (event.request.method !== 'GET') { | ||
return; | ||
} | ||
var origin = self.location.origin; | ||
var key = event.request.url.substring(origin.length + 1); | ||
// Redirect URLs to the index.html | ||
if (key.indexOf('?v=') != -1) { | ||
key = key.split('?v=')[0]; | ||
} | ||
if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') { | ||
key = '/'; | ||
} | ||
// If the URL is not the RESOURCE list then return to signal that the | ||
// browser should take over. | ||
if (!RESOURCES[key]) { | ||
return; | ||
} | ||
// If the URL is the index.html, perform an online-first request. | ||
if (key == '/') { | ||
return onlineFirst(event); | ||
} | ||
event.respondWith(caches.open(CACHE_NAME) | ||
.then((cache) => { | ||
return cache.match(event.request).then((response) => { | ||
// Either respond with the cached resource, or perform a fetch and | ||
// lazily populate the cache only if the resource was successfully fetched. | ||
return response || fetch(event.request).then((response) => { | ||
if (response && Boolean(response.ok)) { | ||
cache.put(event.request, response.clone()); | ||
} | ||
return response; | ||
}); | ||
}) | ||
}) | ||
); | ||
}); | ||
|
||
self.addEventListener('message', (event) => { | ||
// SkipWaiting can be used to immediately activate a waiting service worker. | ||
// This will also require a page refresh triggered by the main worker. | ||
if (event.data === 'skipWaiting') { | ||
self.skipWaiting(); | ||
return; | ||
} | ||
if (event.data === 'downloadOffline') { | ||
downloadOffline(); | ||
return; | ||
} | ||
}); | ||
|
||
// Download offline will check the RESOURCES for all files not in the cache | ||
// and populate them. | ||
async function downloadOffline() { | ||
var resources = []; | ||
var contentCache = await caches.open(CACHE_NAME); | ||
var currentContent = {}; | ||
for (var request of await contentCache.keys()) { | ||
var key = request.url.substring(origin.length + 1); | ||
if (key == "") { | ||
key = "/"; | ||
} | ||
currentContent[key] = true; | ||
} | ||
for (var resourceKey of Object.keys(RESOURCES)) { | ||
if (!currentContent[resourceKey]) { | ||
resources.push(resourceKey); | ||
} | ||
} | ||
return contentCache.addAll(resources); | ||
} | ||
|
||
// Attempt to download the resource online before falling back to | ||
// the offline cache. | ||
function onlineFirst(event) { | ||
return event.respondWith( | ||
fetch(event.request).then((response) => { | ||
return caches.open(CACHE_NAME).then((cache) => { | ||
cache.put(event.request, response.clone()); | ||
return response; | ||
}); | ||
}).catch((error) => { | ||
return caches.open(CACHE_NAME).then((cache) => { | ||
return cache.match(event.request).then((response) => { | ||
if (response != null) { | ||
return response; | ||
} | ||
throw error; | ||
}); | ||
}); | ||
}) | ||
); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.