VulpesOS/gaia/distros/spark/apps/customizer-launcher/components/fxos-achievements-service/achievements-service.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

144 lines
4.6 KiB
JavaScript
Executable file

'use strict';
/* global Notification, console */
const DEFAULT_IMAGE_SIZE = 64;
const MOZ_SETTINGS_NOT_AVAILABLE_MSG = 'navigator.mozSettings is not available';
class ImageHelper {
static getImage(aSrc) {
return new Promise((resolve, reject) => {
let image = new Image();
image.src = aSrc;
image.onload = () => resolve(image);
image.onerror = reason => reject(reason);
}).catch(reason => console.warn('Could not load an achievement image:',
reason));
}
/**
* Generate a Data URL for an image from source.
* @param {String} aSrc source path to the image
* @return {Promise} a promise of Data URL.
*/
static generateImageDataURL(aSrc) {
return ImageHelper.getImage(aSrc).then(image => {
try {
let canvas = document.createElement('canvas');
canvas.height = canvas.width = DEFAULT_IMAGE_SIZE;
let context = canvas.getContext('2d');
let dataUrl;
context.drawImage(image, 0, 0, DEFAULT_IMAGE_SIZE, DEFAULT_IMAGE_SIZE);
dataUrl = canvas.toDataURL();
// Clean up.
canvas.width = canvas.height = 0;
canvas = null;
return dataUrl;
} catch(e) {
return Promise.reject('Could not convert image to Data URL.');
}
}).catch(reason => console.warn(reason));
}
}
class SettingsHelper {
static get(name, defaultValue) {
if (!name) {
return Promise.reject('Setting name is missing');
}
if (!navigator.mozSettings) {
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
}
return new Promise((resolve, reject) => {
let setting = navigator.mozSettings.createLock().get(name, defaultValue);
setting.onsuccess = () => {
let settingValue = setting.result[name] || defaultValue;
resolve(settingValue);
};
setting.onerror = () => { reject(setting.error); };
});
}
static set(settings) {
if (!settings) {
return Promise.reject('Settings are missing');
}
if (!navigator.mozSettings) {
console.warn(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
return Promise.reject(MOZ_SETTINGS_NOT_AVAILABLE_MSG);
}
return new Promise((resolve, reject) => {
let result = navigator.mozSettings.createLock().set(settings);
result.onsuccess = () => { resolve(result.result); };
result.onerror = () => { reject(result.error); };
});
}
}
export default class AchievementsService {
/**
* Reward an achievement and store a record in 'achievements' setting.
* @param {JSON} options attributes for the achievement that is awarded:
* {String} criteria URL of the criteria for earning
* the achievement
* {String} evidence A URN of the evidence of
* achievement unlocked
* {String} name Achievement name
* {String} description Achievement description
* {String} image Achievement image
*/
reward({criteria, evidence, name, description, image}) {
if (!evidence) {
return Promise.reject('Evidence is not provided.');
}
let issuedOn;
return SettingsHelper.get('achievements', []).then(achievements => {
let achievement = achievements.find(
achievement => achievement.criteria === criteria);
if (!achievement) {
return Promise.reject('Achievement is not registered.');
}
if (achievement.evidence) {
return Promise.reject('Achievement is already awarded.');
}
achievement.evidence = evidence;
achievement.uid = 'achievement' + Math.round(Math.random() * 100000000);
achievement.issuedOn = issuedOn = Date.now();
achievement.recipient = {}; // TODO
return achievements;
}).then(achievements => Promise.all([
ImageHelper.generateImageDataURL(image),
SettingsHelper.set({ 'achievements': achievements })
])).then(([image]) => {
// Send a Notification via WebAPI to be handled by the Gaia::System
let notification = new Notification(name, {
body: description,
icon: image,
tag: issuedOn
});
notification.onclick = () => {
let activity = new window.MozActivity({
name: 'configure',
data: {
target: 'device',
section: 'achievements'
}
});
activity.onsuccess = activity.onerror = () => { notification.close(); };
};
}).catch(reason => console.warn(reason));
}
}