Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
247 lines
8.3 KiB
JavaScript
Executable file
247 lines
8.3 KiB
JavaScript
Executable file
/* global CustomDialog, NotificationHelper */
|
|
'use strict';
|
|
|
|
screen.mozLockOrientation('portrait');
|
|
|
|
// This page can be launched in one of two ways: as an activity opened by
|
|
// another app, or by clicking the "+" icon in the ringtone manager. First up,
|
|
// let's handle the activity case.
|
|
if (document.location.hash === '#activity') {
|
|
navigator.mozSetMessageHandler('activity', function(activity) {
|
|
// Turn an array of data into its first element; we need this to make
|
|
// "share" activity data look more like "pick" activity data. We still want
|
|
// to preserve the rest of the structure though, so that other attributes
|
|
// get passed along.
|
|
function flatten(arr) {
|
|
return arr && arr.length ? arr[0] : null;
|
|
}
|
|
|
|
var data = activity.source.data;
|
|
data.blob = flatten(data.blobs);
|
|
data.metadata = flatten(data.metadata);
|
|
data.name = flatten(data.filenames);
|
|
|
|
handleShare(data, function(command, details) {
|
|
switch (command) {
|
|
case 'save':
|
|
activity.postResult({});
|
|
break;
|
|
|
|
case 'cancel':
|
|
activity.postError('pick cancelled');
|
|
break;
|
|
|
|
case 'error':
|
|
activity.postError('pick error');
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
else {
|
|
// XXX: If this window was opened from the ringtones manager and we lose
|
|
// visibility, we need to close the window so that subsequent calls to
|
|
// window.open actually bring the window to the foreground! This is a
|
|
// workaround for the fact that the ringtones app is currently has a "system"
|
|
// role, which means that it doesn't participate in the window manager's
|
|
// stack. See bug 1030954 for more details.
|
|
window.addEventListener('visibilitychange', function() {
|
|
if (document.hidden) {
|
|
window.close();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('message', function(event) {
|
|
if (event.origin !== window.location.origin) {
|
|
console.error('Couldn\'t recieve message: origins don\'t match',
|
|
event.origin, window.location.origin);
|
|
return;
|
|
}
|
|
|
|
handleShare(event.data, function(command, details) {
|
|
event.source.postMessage(
|
|
{command: command, details: details}, event.origin
|
|
);
|
|
window.close();
|
|
});
|
|
});
|
|
}
|
|
|
|
function handleShare(data, callback) {
|
|
navigator.mozL10n.once(function() {
|
|
|
|
function showError(title, message, okCallback) {
|
|
var okButton = {
|
|
title: 'ok',
|
|
callback: function() {
|
|
CustomDialog.hide();
|
|
okCallback();
|
|
}
|
|
};
|
|
CustomDialog.show(title, message, okButton);
|
|
}
|
|
|
|
var save = document.getElementById('save');
|
|
var header = document.getElementById('header');
|
|
var control = document.getElementById('playpause');
|
|
var preview = document.getElementById('preview');
|
|
|
|
var songtitle;
|
|
if (data.metadata && data.metadata.title) {
|
|
songtitle = data.metadata.title;
|
|
}
|
|
else if (data.name) {
|
|
songtitle = data.name;
|
|
}
|
|
else {
|
|
songtitle = 'ringtone-untitled';
|
|
}
|
|
|
|
var subtitle = '';
|
|
if (data.metadata && data.metadata.artist) {
|
|
subtitle = data.metadata.artist;
|
|
}
|
|
|
|
document.getElementById('songtitle').textContent = songtitle;
|
|
document.getElementById('artist').textContent = subtitle;
|
|
|
|
if (data.metadata && data.metadata.picture) {
|
|
// If we have a picture, make sure the subtitle takes up some vertical
|
|
// space so that everything lines up correctly.
|
|
if (!subtitle) {
|
|
document.getElementById('artist').textContent = '\u00a0'; //
|
|
}
|
|
|
|
try {
|
|
var pictureURL = URL.createObjectURL(data.metadata.picture);
|
|
var picture = document.getElementById('picture');
|
|
picture.hidden = false;
|
|
picture.style.backgroundImage = 'url(' + pictureURL + ')';
|
|
}
|
|
catch(e) {
|
|
console.error('Couldn\'t set picture:', e);
|
|
}
|
|
}
|
|
|
|
control.addEventListener('click', function() {
|
|
if (preview.paused) {
|
|
// HACK HACK HACK
|
|
//
|
|
// This is an ugly workaround for bug 956811.
|
|
//
|
|
// Bugs in the system app window manager and Gecko's audio
|
|
// channel manager prevent the music app from being paused when
|
|
// this set ringtone app previews a ringtone. As a workaround,
|
|
// the music app listens to the settings database and will pause
|
|
// itself if we set a magic property that it specifies. So if
|
|
// the activity data includes a special magic property then we
|
|
// know that we were invoked by the music app, and the music app
|
|
// is playing a song. The value of the property in the activity
|
|
// data is the name of the property in the settings database
|
|
// that it is listening to.
|
|
//
|
|
// See also the corresponding code in apps/music/js/Player.js
|
|
//
|
|
// This hack is implemented as a single self-invoking function so it is
|
|
// easy to remove when we have a proper bug fix.
|
|
//
|
|
// HACK HACK HACK
|
|
(function() {
|
|
var hack_activity_property = '_hack_hack_shut_up';
|
|
var hack_settings_property = data[hack_activity_property];
|
|
if (hack_settings_property) {
|
|
// Query the value of this setting
|
|
var lock = navigator.mozSettings.createLock();
|
|
lock.get(hack_settings_property).onsuccess = function(e) {
|
|
var value = e.target.result[hack_settings_property];
|
|
|
|
// Once we have the value, set the setting to something different.
|
|
// This should pause the music app. Wait until we have
|
|
// confirmation that the setting was set before starting to play
|
|
// the preview so that the music app has time to pause first
|
|
var o = {};
|
|
o[hack_settings_property] = !value;
|
|
navigator.mozSettings.createLock().set(o).onsuccess = function() {
|
|
preview.play();
|
|
};
|
|
|
|
// Alter the activity data so we only run this code once.
|
|
delete data[hack_activity_property];
|
|
};
|
|
}
|
|
else {
|
|
preview.play();
|
|
}
|
|
}());
|
|
// END OF HACK
|
|
// When there is a real bug fix, just replace this entire if clause
|
|
// with:
|
|
// preview.play();
|
|
}
|
|
else {
|
|
preview.pause();
|
|
}
|
|
});
|
|
|
|
preview.src = URL.createObjectURL(data.blob);
|
|
|
|
preview.addEventListener('canplay', function() {
|
|
save.disabled = false;
|
|
});
|
|
|
|
preview.addEventListener('error', function() {
|
|
showError('play-error-title', 'play-error-desc',
|
|
callback.bind(null, 'error'));
|
|
});
|
|
|
|
preview.addEventListener('playing', function() {
|
|
control.classList.add('playing');
|
|
});
|
|
|
|
preview.addEventListener('pause', function() {
|
|
control.classList.remove('playing');
|
|
});
|
|
|
|
header.addEventListener('action', function() {
|
|
callback('cancel');
|
|
});
|
|
|
|
save.addEventListener('click', function() {
|
|
// Disable the button so the user can't click it twice.
|
|
save.disabled = true;
|
|
|
|
// For a large blob this can take a while, so display a spinner.
|
|
document.getElementById('saving-overlay').hidden = false;
|
|
|
|
// Add to the custom ringtones DB and then set it in the settings.
|
|
var info = {name: songtitle, subtitle: subtitle, blob: data.blob};
|
|
window.customRingtones.add(info).then(function(tone) {
|
|
if (document.getElementById('default-switch').checked) {
|
|
return window.systemTones.set('ringtone', tone).then(function() {
|
|
return {toneID: tone.id, setAsDefault: true};
|
|
});
|
|
}
|
|
|
|
return {toneID: tone.id, setAsDefault: false};
|
|
}).then(function(details) {
|
|
// Show a notification indicating success, and then close it immediately
|
|
// so it doesn't stink up the notifications tray! XXX: This UX isn't
|
|
// great; we should turn this into a transient notification when we can.
|
|
NotificationHelper.send(
|
|
songtitle,
|
|
{ bodyL10n: details.setAsDefault ? 'set-default-tone' :
|
|
'created-tone',
|
|
closeOnClick: false
|
|
}
|
|
).then((notification) => {
|
|
notification.close();
|
|
callback('save', details);
|
|
});
|
|
}, function(error) {
|
|
console.log('Error saving ringtone', error);
|
|
showError('save-error-title', 'save-error-desc',
|
|
callback.bind(null, 'error'));
|
|
});
|
|
});
|
|
});
|
|
}
|