-
Notifications
You must be signed in to change notification settings - Fork 0
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
Denny
committed
Feb 26, 2023
0 parents
commit 42c775c
Showing
27 changed files
with
77,346 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
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 @@ | ||
{"assets/images/animal.png":["assets/images/animal.png"],"assets/images/appstore.png":["assets/images/appstore.png"],"assets/images/bprecord.png":["assets/images/bprecord.png"],"assets/images/palette.png":["assets/images/palette.png"],"assets/images/play_download.png":["assets/images/play_download.png"],"assets/images/qrscan.png":["assets/images/qrscan.png"]} |
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"}]}] |
Large diffs are not rendered by default.
Oops, something went wrong.
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.
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.
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,362 @@ | ||
// 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. | ||
|
||
if (!_flutter) { | ||
var _flutter = {}; | ||
} | ||
_flutter.loader = null; | ||
|
||
(function () { | ||
"use strict"; | ||
/** | ||
* Wraps `promise` in a timeout of the given `duration` in ms. | ||
* | ||
* Resolves/rejects with whatever the original `promises` does, or rejects | ||
* if `promise` takes longer to complete than `duration`. In that case, | ||
* `debugName` is used to compose a legible error message. | ||
* | ||
* If `duration` is < 0, the original `promise` is returned unchanged. | ||
* @param {Promise} promise | ||
* @param {number} duration | ||
* @param {string} debugName | ||
* @returns {Promise} a wrapped promise. | ||
*/ | ||
async function timeout(promise, duration, debugName) { | ||
if (duration < 0) { | ||
return promise; | ||
} | ||
let timeoutId; | ||
const _clock = new Promise((_, reject) => { | ||
timeoutId = setTimeout(() => { | ||
reject( | ||
new Error( | ||
`${debugName} took more than ${duration}ms to resolve. Moving on.`, | ||
{ | ||
cause: timeout, | ||
} | ||
) | ||
); | ||
}, duration); | ||
}); | ||
|
||
return Promise.race([promise, _clock]).finally(() => { | ||
clearTimeout(timeoutId); | ||
}); | ||
} | ||
|
||
/** | ||
* Handles the creation of a TrustedTypes `policy` that validates URLs based | ||
* on an (optional) incoming array of RegExes. | ||
*/ | ||
class FlutterTrustedTypesPolicy { | ||
/** | ||
* Constructs the policy. | ||
* @param {[RegExp]} validPatterns the patterns to test URLs | ||
* @param {String} policyName the policy name (optional) | ||
*/ | ||
constructor(validPatterns, policyName = "flutter-js") { | ||
const patterns = validPatterns || [ | ||
/\.dart\.js$/, | ||
/^flutter_service_worker.js$/ | ||
]; | ||
if (window.trustedTypes) { | ||
this.policy = trustedTypes.createPolicy(policyName, { | ||
createScriptURL: function(url) { | ||
const parsed = new URL(url, window.location); | ||
const file = parsed.pathname.split("/").pop(); | ||
const matches = patterns.some((pattern) => pattern.test(file)); | ||
if (matches) { | ||
return parsed.toString(); | ||
} | ||
console.error( | ||
"URL rejected by TrustedTypes policy", | ||
policyName, ":", url, "(download prevented)"); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Handles loading/reloading Flutter's service worker, if configured. | ||
* | ||
* @see: https://developers.google.com/web/fundamentals/primers/service-workers | ||
*/ | ||
class FlutterServiceWorkerLoader { | ||
/** | ||
* Injects a TrustedTypesPolicy (or undefined if the feature is not supported). | ||
* @param {TrustedTypesPolicy | undefined} policy | ||
*/ | ||
setTrustedTypesPolicy(policy) { | ||
this._ttPolicy = policy; | ||
} | ||
|
||
/** | ||
* Returns a Promise that resolves when the latest Flutter service worker, | ||
* configured by `settings` has been loaded and activated. | ||
* | ||
* Otherwise, the promise is rejected with an error message. | ||
* @param {*} settings Service worker settings | ||
* @returns {Promise} that resolves when the latest serviceWorker is ready. | ||
*/ | ||
loadServiceWorker(settings) { | ||
if (!("serviceWorker" in navigator) || settings == null) { | ||
// In the future, settings = null -> uninstall service worker? | ||
return Promise.reject( | ||
new Error("Service worker not supported (or configured).") | ||
); | ||
} | ||
const { | ||
serviceWorkerVersion, | ||
serviceWorkerUrl = "flutter_service_worker.js?v=" + | ||
serviceWorkerVersion, | ||
timeoutMillis = 4000, | ||
} = settings; | ||
|
||
// Apply the TrustedTypes policy, if present. | ||
let url = serviceWorkerUrl; | ||
if (this._ttPolicy != null) { | ||
url = this._ttPolicy.createScriptURL(url); | ||
} | ||
|
||
const serviceWorkerActivation = navigator.serviceWorker | ||
.register(url) | ||
.then(this._getNewServiceWorker) | ||
.then(this._waitForServiceWorkerActivation); | ||
|
||
// Timeout race promise | ||
return timeout( | ||
serviceWorkerActivation, | ||
timeoutMillis, | ||
"prepareServiceWorker" | ||
); | ||
} | ||
|
||
/** | ||
* Returns the latest service worker for the given `serviceWorkerRegistrationPromise`. | ||
* | ||
* This might return the current service worker, if there's no new service worker | ||
* awaiting to be installed/updated. | ||
* | ||
* @param {Promise<ServiceWorkerRegistration>} serviceWorkerRegistrationPromise | ||
* @returns {Promise<ServiceWorker>} | ||
*/ | ||
async _getNewServiceWorker(serviceWorkerRegistrationPromise) { | ||
const reg = await serviceWorkerRegistrationPromise; | ||
|
||
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. | ||
console.debug("Installing/Activating first service worker."); | ||
return 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. | ||
return reg.update().then((newReg) => { | ||
console.debug("Updating service worker."); | ||
return newReg.installing || newReg.waiting || newReg.active; | ||
}); | ||
} else { | ||
console.debug("Loading from existing service worker."); | ||
return reg.active; | ||
} | ||
} | ||
|
||
/** | ||
* Returns a Promise that resolves when the `latestServiceWorker` changes its | ||
* state to "activated". | ||
* | ||
* @param {Promise<ServiceWorker>} latestServiceWorkerPromise | ||
* @returns {Promise<void>} | ||
*/ | ||
async _waitForServiceWorkerActivation(latestServiceWorkerPromise) { | ||
const serviceWorker = await latestServiceWorkerPromise; | ||
|
||
if (!serviceWorker || serviceWorker.state == "activated") { | ||
if (!serviceWorker) { | ||
return Promise.reject( | ||
new Error("Cannot activate a null service worker!") | ||
); | ||
} else { | ||
console.debug("Service worker already active."); | ||
return Promise.resolve(); | ||
} | ||
} | ||
return new Promise((resolve, _) => { | ||
serviceWorker.addEventListener("statechange", () => { | ||
if (serviceWorker.state == "activated") { | ||
console.debug("Activated new service worker."); | ||
resolve(); | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying | ||
* the user when Flutter is ready, through `didCreateEngineInitializer`. | ||
* | ||
* @see https://docs.flutter.dev/development/platform-integration/web/initialization | ||
*/ | ||
class FlutterEntrypointLoader { | ||
/** | ||
* Creates a FlutterEntrypointLoader. | ||
*/ | ||
constructor() { | ||
// Watchdog to prevent injecting the main entrypoint multiple times. | ||
this._scriptLoaded = false; | ||
} | ||
|
||
/** | ||
* Injects a TrustedTypesPolicy (or undefined if the feature is not supported). | ||
* @param {TrustedTypesPolicy | undefined} policy | ||
*/ | ||
setTrustedTypesPolicy(policy) { | ||
this._ttPolicy = policy; | ||
} | ||
|
||
/** | ||
* Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a | ||
* user-specified `onEntrypointLoaded` callback with an EngineInitializer | ||
* object when it's done. | ||
* | ||
* @param {*} options | ||
* @returns {Promise | undefined} that will eventually resolve with an | ||
* EngineInitializer, or will be rejected with the error caused by the loader. | ||
* Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`. | ||
*/ | ||
async loadEntrypoint(options) { | ||
const { entrypointUrl = "main.dart.js", onEntrypointLoaded } = | ||
options || {}; | ||
|
||
return this._loadEntrypoint(entrypointUrl, onEntrypointLoaded); | ||
} | ||
|
||
/** | ||
* Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded` | ||
* function supplied by the user (if needed). | ||
* | ||
* Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method, | ||
* which is bound to the correct instance of the FlutterEntrypointLoader by | ||
* the FlutterLoader object. | ||
* | ||
* @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42 | ||
*/ | ||
didCreateEngineInitializer(engineInitializer) { | ||
if (typeof this._didCreateEngineInitializerResolve === "function") { | ||
this._didCreateEngineInitializerResolve(engineInitializer); | ||
// Remove the resolver after the first time, so Flutter Web can hot restart. | ||
this._didCreateEngineInitializerResolve = null; | ||
// Make the engine revert to "auto" initialization on hot restart. | ||
delete _flutter.loader.didCreateEngineInitializer; | ||
} | ||
if (typeof this._onEntrypointLoaded === "function") { | ||
this._onEntrypointLoaded(engineInitializer); | ||
} | ||
} | ||
|
||
/** | ||
* Injects a script tag into the DOM, and configures this loader to be able to | ||
* handle the "entrypoint loaded" notifications received from Flutter web. | ||
* | ||
* @param {string} entrypointUrl the URL of the script that will initialize | ||
* Flutter. | ||
* @param {Function} onEntrypointLoaded a callback that will be called when | ||
* Flutter web notifies this object that the entrypoint is | ||
* loaded. | ||
* @returns {Promise | undefined} a Promise that resolves when the entrypoint | ||
* is loaded, or undefined if `onEntrypointLoaded` | ||
* is a function. | ||
*/ | ||
_loadEntrypoint(entrypointUrl, onEntrypointLoaded) { | ||
const useCallback = typeof onEntrypointLoaded === "function"; | ||
|
||
if (!this._scriptLoaded) { | ||
this._scriptLoaded = true; | ||
const scriptTag = this._createScriptTag(entrypointUrl); | ||
if (useCallback) { | ||
// Just inject the script tag, and return nothing; Flutter will call | ||
// `didCreateEngineInitializer` when it's done. | ||
console.debug("Injecting <script> tag. Using callback."); | ||
this._onEntrypointLoaded = onEntrypointLoaded; | ||
document.body.append(scriptTag); | ||
} else { | ||
// Inject the script tag and return a promise that will get resolved | ||
// with the EngineInitializer object from Flutter when it calls | ||
// `didCreateEngineInitializer` later. | ||
return new Promise((resolve, reject) => { | ||
console.debug( | ||
"Injecting <script> tag. Using Promises. Use the callback approach instead!" | ||
); | ||
this._didCreateEngineInitializerResolve = resolve; | ||
scriptTag.addEventListener("error", reject); | ||
document.body.append(scriptTag); | ||
}); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Creates a script tag for the given URL. | ||
* @param {string} url | ||
* @returns {HTMLScriptElement} | ||
*/ | ||
_createScriptTag(url) { | ||
const scriptTag = document.createElement("script"); | ||
scriptTag.type = "application/javascript"; | ||
// Apply TrustedTypes validation, if available. | ||
let trustedUrl = url; | ||
if (this._ttPolicy != null) { | ||
trustedUrl = this._ttPolicy.createScriptURL(url); | ||
} | ||
scriptTag.src = trustedUrl; | ||
return scriptTag; | ||
} | ||
} | ||
|
||
/** | ||
* The public interface of _flutter.loader. Exposes two methods: | ||
* * loadEntrypoint (which coordinates the default Flutter web loading procedure) | ||
* * didCreateEngineInitializer (which is called by Flutter to notify that its | ||
* Engine is ready to be initialized) | ||
*/ | ||
class FlutterLoader { | ||
/** | ||
* Initializes the Flutter web app. | ||
* @param {*} options | ||
* @returns {Promise?} a (Deprecated) Promise that will eventually resolve | ||
* with an EngineInitializer, or will be rejected with | ||
* any error caused by the loader. Or Null, if the user | ||
* supplies an `onEntrypointLoaded` Function as an option. | ||
*/ | ||
async loadEntrypoint(options) { | ||
const { serviceWorker, ...entrypoint } = options || {}; | ||
|
||
// A Trusted Types policy that is going to be used by the loader. | ||
const flutterTT = new FlutterTrustedTypesPolicy(); | ||
|
||
// The FlutterServiceWorkerLoader instance could be injected as a dependency | ||
// (and dynamically imported from a module if not present). | ||
const serviceWorkerLoader = new FlutterServiceWorkerLoader(); | ||
serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy); | ||
await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => { | ||
// Regardless of what happens with the injection of the SW, the show must go on | ||
console.warn("Exception while loading service worker:", e); | ||
}); | ||
|
||
// The FlutterEntrypointLoader instance could be injected as a dependency | ||
// (and dynamically imported from a module if not present). | ||
const entrypointLoader = new FlutterEntrypointLoader(); | ||
entrypointLoader.setTrustedTypesPolicy(flutterTT.policy); | ||
// Install the `didCreateEngineInitializer` listener where Flutter web expects it to be. | ||
this.didCreateEngineInitializer = | ||
entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader); | ||
return entrypointLoader.loadEntrypoint(entrypoint); | ||
} | ||
} | ||
|
||
_flutter.loader = new FlutterLoader(); | ||
})(); | ||
|
Oops, something went wrong.