blob: 2ba18f0e1486aa13366421f113c5d8d9a86a98f5 [file] [log] [blame]
/**
* @module skottie-drive-sk
* @description <h2><code>skottie-drive-sk</code></h2>
*
* Presents a page for previewing Lottie files that are coming
* from Google Drive.
*
* All the work in the app is done in the browser, i.e. no server side
* work is done. Authentication is done via the Google JS client library
* and rendering of the Lottie files is done using the WASM version of
* Skia.
*
* A link from Google Drive to preview a JSON file will include a query
* parameter named 'state' that looks like:
*
* {
* "ids": ["0Bz0bd"],
* "action":"open",
* "userId":"103354693083460731603"
* }
*
* Where 'ids' is a list of Google Drive document ids that can be used
* via the Google Drive API to retrieve the document or metadata about
* the document.
*
*/
import '../skottie-player-sk'
import 'elements-sk/error-toast-sk'
import { $$ } from 'common-sk/modules/dom'
import { SKIA_VERSION } from '../../build/version.js'
import { define } from 'elements-sk/define'
import { errorMessage } from 'elements-sk/errorMessage'
import { html, render } from 'lit-html'
import { until } from 'lit-html/directives/until.js';
// gapiLoaded is a promise that resolves when the 'gapi' JS library is
// finished loading.
let gapiLoaded = new Promise((resolve, reject) => {
let check = () => {
if (window.gapi !== undefined) {
resolve();
} else {
setTimeout(check, 10)
}
}
setTimeout(check, 10)
});
// caption returns a promise that resolves to the filename of the document
// with the given drive id.
const caption = (id) => {
return gapiLoaded.then(() => {
// Metadata.
return gapi.client.drive.files.get({
alt: 'json',
fileId: id,
}).then((response) => {
return html`<pre>${response.result.name}</pre>`;
}).catch((response) => {
errorMessage(response.result.error.message, 0);
});
});
}
// players returns one <skottie-player-sk> for each id.
const players = (ele) => ele._ids.map((id, i) => html`
<figure>
<skottie-player-sk id="x${i}"></skottie-player-sk>
<figcaption><p>${until(caption(id), `Loading...`)}</p><p class=errors id="errors${i}"></p></figcaption>
</figure>`);
const template = (ele) => html`
<header>
<h2>Skia Lottie Drive Previewer</h2><span><a href='https://skia.googlesource.com/skia/+/${SKIA_VERSION}'>${SKIA_VERSION.slice(0, 7)}</a></span>
</header>
<main>
${players(ele)}
</main>
<footer>
<error-toast-sk></error-toast-sk>
</footer>
`;
define('skottie-drive-sk', class extends HTMLElement {
constructor() {
super();
// The list of ids of documents to display.
this._ids = [];
}
connectedCallback() {
this._render();
gapiLoaded.then(() => {
// Load both the JS Apiary client library and OAuth 2 client library.
gapi.load('client:auth2', () => { this.initClient() });
});
}
initClient() {
let postInit = () => {
let isSignedIn = gapi.auth2.getAuthInstance().isSignedIn;
// Listen for sign-in state changes.
isSignedIn.listen(this.updateSigninStatus);
// Handle the initial sign-in state.
this.updateSigninStatus(isSignedIn.get());
};
gapi.client.init({
apiKey: 'AIzaSyD2US0bcYT2VhguMezYgDa4lbZc6rIQbDg', // API Key is locked to https://skottie.skia.org, so it's safe to hardcode here.
clientId: '145247227042-fetft5vnkf582o817e1t553cm3tjvobl.apps.googleusercontent.com', // Not protected info (clientSecret would be).
discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'],
scope: 'https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/drive.install',
}).then(postInit);
}
// updateSigninStatus is called when the signed in status changes.
updateSigninStatus(isSignedIn) {
if (!isSignedIn) {
gapi.auth2.getAuthInstance().signIn();
} else {
this.loadFiles();
}
}
loadFiles() {
// The state parameter is JSON that looks like:
//
// {
// "ids": ["0Bz0bd"],
// "action":"open",
// "userId":"103354693083460731603"
// }
//
// See https://developers.google.com/drive/api/v3/integrate-open for more
// details.
let ids = ['12M0hlsK-zYCrKU6TG-Bji5Kcr9hWoyJw'];
let stateParam = (new URL(document.location)).searchParams.get('state');
if (stateParam) {
ids = JSON.parse(stateParam).ids;
}
// Render a <skottie-player-sk> for each id.
this._ids = ids;
this._render();
// Now kick off a fetch request for each player that retrieves the JSON
// and populates the player.
ids.forEach((id, i) => {
// Media.
gapi.client.drive.files.get({
alt: 'media',
fileId: id,
}).then((response) => {
if (response.headers['Content-Type'] !== 'application/json') {
$$(`#errors${i}`, this).textContent = `Error: Not a JSON file.`;
errorMessage("Can only process JSON files.", 0);
return;
}
let lottie = response.result;
let init = {
width : lottie.w || 128,
height : lottie.h || 128,
lottie : lottie,
}
$$(`#x${i}`, this).initialize(init).catch((msg) => {
$$(`#errors${i}`, this).textContent = `Error: Not a valid Lottie file.`;
errorMessage(msg, 0);
});
}).catch((response) => {
errorMessage(response.result.error.message, 0);
});
});
}
_render() {
render(template(this), this, {eventContext: this});
}
});