VulpesOS/gaia/apps/network-alerts/js/attention/notify.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

120 lines
3 KiB
JavaScript
Executable file

/* global
AudioContext
*/
(function(exports) {
'use strict';
const SETTINGS = {
notificationVolume: 'audio.volume.notification',
vibration: 'vibration.enabled'
};
const ATTENTION_PATTERN = [4, 1, 2, 1, 2, 1];
ATTENTION_PATTERN.push(...ATTENTION_PATTERN);
const ATTENTION_SOUND_VOLUME = 0.3;
function getSetting(key) {
if (!navigator.mozSettings) {
return Promise.reject(new Error('The mozSettings API is not available.'));
}
return navigator.mozSettings.createLock().get(key).then(
(result) => result[key]
);
}
function getSettings(settings) {
return Promise.all(
settings.map(getSetting)
).catch((e) => {
// catch and log errors
console.error('Error while retrieving settings', e.message, e);
return settings.map(() => null);
}).then((results) => {
return settings.reduce((result, setting, i) => {
result[setting] = results[i];
return result;
}, {});
});
}
// Converts from the ATTENTION_PATTERN (suitable for the Vibration API) to a
// Float32Array suitable for the Audio API.
//
// The Float32Array will be interpolated so we just need to have the changes.
// Each value will last a "unit" of time.
function getAttentionCurveWave() {
var result = [];
var currentValue = ATTENTION_SOUND_VOLUME;
ATTENTION_PATTERN.forEach(duration => {
for (var i = 0; i < duration; i++) {
result.push(currentValue);
}
currentValue = ATTENTION_SOUND_VOLUME - currentValue;
});
return new Float32Array(result);
}
function ringtone() {
var audioChannel = 'notification';
var audioCtx = new AudioContext(audioChannel);
var o1 = audioCtx.createOscillator();
var o2 = audioCtx.createOscillator();
var gain = audioCtx.createGain();
var time = audioCtx.currentTime;
o1.type = o2.type = 'sine';
o1.frequency.value = 853;
o2.frequency.value = 960;
o1.start();
o2.start();
// Eventually stop the oscillator to allow garbage collecting.
o1.stop(time + 11);
o2.stop(time + 11);
var wave = getAttentionCurveWave();
gain.gain.setValueCurveAtTime(wave, time, 11);
o1.connect(gain);
o2.connect(gain);
gain.connect(audioCtx.destination);
}
function vibrate() {
var pattern = ATTENTION_PATTERN.map((value) => value * 500);
// vibration only works when App is in the foreground
if (document.hidden) {
window.addEventListener('visibilitychange', function waitOn() {
window.removeEventListener('visibilitychange', waitOn);
navigator.vibrate(pattern);
});
} else {
navigator.vibrate(pattern);
}
}
var Notify = {
notify: function notification_ringtone() {
return getSettings(
[SETTINGS.notificationVolume, SETTINGS.vibration]
).then((settings) => {
if (settings[SETTINGS.notificationVolume]) {
ringtone();
}
if (settings[SETTINGS.vibration]) {
vibrate();
}
});
}
};
exports.Notify = Notify;
}(this));