Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
318 lines
8.2 KiB
JavaScript
Executable file
318 lines
8.2 KiB
JavaScript
Executable file
define(function(require) {
|
|
'use strict';
|
|
/* global IntlHelper */
|
|
|
|
var Panel = require('panel');
|
|
var Picker = require('picker/picker');
|
|
var View = require('view');
|
|
|
|
var Utils = require('utils');
|
|
var Timer = require('timer');
|
|
var Sounds = require('sounds');
|
|
var FormButton = require('form_button');
|
|
var html = require('text!panels/timer/panel.html');
|
|
var AudioManager = require('audio_manager');
|
|
var asyncStorage = require('shared/js/async_storage');
|
|
|
|
var priv = new WeakMap();
|
|
|
|
function timeFromPicker(value) {
|
|
var hm, ms;
|
|
hm = value.split(':');
|
|
ms = Utils.dateMath.toMS({
|
|
hours: hm[0],
|
|
minutes: hm[1]
|
|
});
|
|
return ms;
|
|
}
|
|
|
|
IntlHelper.define('timer-hms', 'mozduration', {
|
|
minUnit: 'second',
|
|
maxUnit: 'hour'
|
|
});
|
|
|
|
/**
|
|
* Timer.Panel
|
|
*
|
|
* Construct a UI panel for the Timer panel.
|
|
*
|
|
* @return {Timer.Panel} Timer.Panel object.
|
|
*
|
|
*/
|
|
Timer.Panel = function(element) {
|
|
Panel.apply(this, arguments);
|
|
|
|
element.innerHTML = html;
|
|
this.timer = null;
|
|
this.nodes = {};
|
|
|
|
this.picker = new Picker({
|
|
element: this.element.querySelector('#time-picker'),
|
|
pickers: {
|
|
hours: {
|
|
range: [0, 23],
|
|
l10nId: 'nSpinnerHours'
|
|
},
|
|
minutes: {
|
|
range: [0, 59],
|
|
isPadded: true,
|
|
l10nId: 'nSpinnerMinutes'
|
|
}
|
|
}
|
|
});
|
|
|
|
this.ringtonePlayer = AudioManager.createAudioPlayer();
|
|
|
|
// Gather elements
|
|
[
|
|
'create', 'cancel', 'dialog', 'pause', 'start', 'sound', 'time', 'vibrate',
|
|
'plus'
|
|
].forEach(function(id) {
|
|
this.nodes[id] = this.element.querySelector('#timer-' + id);
|
|
}, this);
|
|
|
|
// Bind click events
|
|
[
|
|
'create', 'cancel', 'pause', 'start', 'plus'
|
|
].forEach(function(action) {
|
|
var element = this.nodes[action];
|
|
|
|
if (priv.has(element)) {
|
|
priv.delete(element);
|
|
}
|
|
|
|
priv.set(element, {
|
|
action: action,
|
|
panel: this
|
|
});
|
|
|
|
element.addEventListener('click', this.onclick.bind(this), false);
|
|
}, this);
|
|
|
|
var sound = this.nodes.sound;
|
|
|
|
sound.addEventListener('blur', this.pauseAlarm.bind(this), false);
|
|
sound.addEventListener('change', this.previewAlarm.bind(this), false);
|
|
|
|
var soundMenuConfig = {
|
|
id: 'timer-sound-menu',
|
|
formatLabel: Sounds.formatLabel
|
|
};
|
|
this.soundButton = new FormButton(sound, soundMenuConfig);
|
|
this.soundButton.refresh();
|
|
|
|
element.addEventListener('panel-visibilitychange',
|
|
this.onvisibilitychange.bind(this));
|
|
|
|
// The start button is disable by default (picker at 00:00 by default)
|
|
this.nodes.create.setAttribute('disabled', 'true');
|
|
|
|
var create = this.nodes.create;
|
|
var picker = this.picker;
|
|
|
|
var enableButton = () => {
|
|
if(timeFromPicker(picker.value) === 0) {
|
|
create.setAttribute('disabled', 'true');
|
|
} else {
|
|
create.removeAttribute('disabled');
|
|
}
|
|
this.saveCurrentSettingsAsDefaults();
|
|
};
|
|
|
|
// The start button is enable if the value of the timer is not 00:00
|
|
picker.nodes.minutes.addEventListener('transitionend', enableButton);
|
|
picker.nodes.hours.addEventListener('transitionend', enableButton);
|
|
|
|
this.restoreDefaults().then(() => {
|
|
enableButton(); // Update the enabled state to match the new defaults.
|
|
});
|
|
|
|
this.nodes.vibrate.addEventListener(
|
|
'change', (e) => this.saveCurrentSettingsAsDefaults());
|
|
this.nodes.sound.addEventListener(
|
|
'change', (e) => this.saveCurrentSettingsAsDefaults());
|
|
|
|
Timer.singleton(function(err, timer) {
|
|
this.timer = timer;
|
|
var onTimerEvent = this.onTimerEvent.bind(this);
|
|
window.addEventListener('timer-start', onTimerEvent);
|
|
window.addEventListener('timer-pause', onTimerEvent);
|
|
window.addEventListener('timer-tick', onTimerEvent);
|
|
window.addEventListener('timer-end', onTimerEvent);
|
|
IntlHelper.observe('timer-hms', this.update.bind(this));
|
|
if (this.visible) {
|
|
// If the timer panel already became visible before we fetched
|
|
// the timer, we must update the display to show the proper
|
|
// timer status.
|
|
this.onvisibilitychange({ detail: { isVisible: true } });
|
|
}
|
|
}.bind(this));
|
|
};
|
|
|
|
Timer.Panel.prototype = Object.create(Panel.prototype);
|
|
|
|
Timer.Panel.prototype.restoreDefaults = function() {
|
|
return new Promise((resolve) => {
|
|
asyncStorage.getItem('timer-defaults', (values) => {
|
|
values = values || {};
|
|
if (values.sound != null) {
|
|
this.soundButton.value = values.sound;
|
|
}
|
|
if (values.time != null) {
|
|
this.picker.value = values.time;
|
|
}
|
|
if (values.vibrate != null) {
|
|
this.nodes.vibrate.checked = values.vibrate;
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
};
|
|
|
|
Timer.Panel.prototype.saveCurrentSettingsAsDefaults = function() {
|
|
asyncStorage.setItem('timer-defaults', {
|
|
sound: this.soundButton.value,
|
|
time: this.picker.value,
|
|
vibrate: this.nodes.vibrate.checked
|
|
});
|
|
};
|
|
|
|
Timer.Panel.prototype.onvisibilitychange = function(evt) {
|
|
var isVisible = evt.detail.isVisible;
|
|
var timer = this.timer;
|
|
|
|
if (isVisible) {
|
|
// No active timer, or timer has expired...
|
|
// - Show the new timer dialog
|
|
if (timer === null || timer.state === Timer.INITIAL) {
|
|
this.showDialog();
|
|
} else {
|
|
// Active timer exists, might be started by an external app, so we need
|
|
// to make sure dialog is hidden and buttons/time are on correct state
|
|
this.toggleButtons();
|
|
this.hideDialog();
|
|
this.update();
|
|
}
|
|
} else {
|
|
this.pauseAlarm();
|
|
}
|
|
};
|
|
|
|
Timer.Panel.prototype._toggleDialog = function(isVisible = true) {
|
|
View.instance(this.nodes.dialog).visible = isVisible;
|
|
return this;
|
|
};
|
|
|
|
Timer.Panel.prototype.showDialog = function() {
|
|
return this._toggleDialog(true);
|
|
};
|
|
|
|
Timer.Panel.prototype.hideDialog = function() {
|
|
return this._toggleDialog(false);
|
|
};
|
|
|
|
Timer.Panel.prototype.onTimerEvent = function(event) {
|
|
switch (event.type) {
|
|
case 'timer-start':
|
|
// new timer dialog should always be hidden during timer-start (even
|
|
// if started from external app)
|
|
this.hideDialog();
|
|
/* falls through */
|
|
case 'timer-pause':
|
|
this.toggleButtons();
|
|
/* falls through */
|
|
case 'timer-tick':
|
|
this.update();
|
|
break;
|
|
case 'timer-end':
|
|
this.showDialog();
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Given milliseconds, render the time as a rounded-to-seconds
|
|
* countdown.
|
|
*/
|
|
Timer.Panel.prototype.update = function() {
|
|
return IntlHelper.get('timer-hms').then(formatter => {
|
|
var remaining = this.timer.remaining;
|
|
var newText = formatter.format(remaining);
|
|
// Use localized caching here to prevent unnecessary DOM repaints.
|
|
if (this._cachedTimerText !== newText) {
|
|
this.nodes.time.textContent = this._cachedTimerText = newText;
|
|
}
|
|
});
|
|
};
|
|
|
|
Timer.Panel.prototype.toggleButtons = function() {
|
|
var nodes = this.nodes;
|
|
var started = this.timer.state === Timer.STARTED;
|
|
|
|
nodes.pause.classList.toggle('hidden', !started);
|
|
nodes.start.classList.toggle('hidden', started);
|
|
};
|
|
|
|
/**
|
|
* previewAlarm Plays the currently selected alarm value on a loop.
|
|
*/
|
|
Timer.Panel.prototype.previewAlarm = function() {
|
|
var ringtoneName = Utils.getSelectedValueByIndex(this.nodes.sound);
|
|
this.ringtonePlayer.playRingtone(ringtoneName);
|
|
};
|
|
|
|
/**
|
|
* pauseAlarm stops the alarm if it is playing
|
|
*/
|
|
Timer.Panel.prototype.pauseAlarm = function() {
|
|
this.ringtonePlayer.pause();
|
|
};
|
|
|
|
/**
|
|
* handleEvent Handler for all panel bound UI events.
|
|
* (`this` context object is not Timer.Panel)
|
|
*
|
|
* @param {Event} event The Event object.
|
|
*/
|
|
Timer.Panel.prototype.onclick = function(event) {
|
|
var meta = priv.get(event.target);
|
|
var panel = meta.panel;
|
|
var nodes = panel.nodes;
|
|
var timer = panel.timer;
|
|
var time;
|
|
|
|
if (meta.action === 'create') {
|
|
time = timeFromPicker(panel.picker.value);
|
|
|
|
if (!time) {
|
|
return;
|
|
}
|
|
|
|
timer.duration = time;
|
|
timer.sound = nodes.sound.value;
|
|
timer.vibrate = nodes.vibrate.checked;
|
|
timer.start();
|
|
|
|
// Hide the new timer dialog
|
|
panel.hideDialog();
|
|
} else if (meta.action === 'plus') {
|
|
timer.plus(+event.target.dataset.value);
|
|
// need to update immediately cause timer might be paused during click
|
|
panel.update();
|
|
} else {
|
|
// meta.action => timer[meta.action]()
|
|
//
|
|
// ie.
|
|
//
|
|
// if start => timer.start()
|
|
// if pause => timer.pause()
|
|
// if cancel => timer.cancel()
|
|
//
|
|
timer[meta.action]();
|
|
}
|
|
|
|
timer.commit();
|
|
};
|
|
|
|
return Timer.Panel;
|
|
});
|