VulpesOS/gaia/apps/communications/contacts/js/utilities/ice_data.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

272 lines
6.7 KiB
JavaScript
Executable file

'use strict';
/* global Cache */
/* global ICEStore */
/**
* Module to handle ICE data across different parts of the application
* This module just know about the internal representation and how
* to deal with share ICE information (which has different format).
*/
(function ICEData(exports) {
if (exports.ICEData) {
return;
}
var localIceContacts = [];
var ICE_CONTACTS_KEY = 'ice-contacts';
var onChangeCallbacks = [];
var onChangeAttached = false;
var pendingChanges = [];
var performingChange = false;
/**
* Loads the local formated data into an internal
* representation.
* @return (Promise) fullfill when the load finish.
*/
function load() {
var iceContactsIds = [
{
id: undefined,
active: false
},
{
id: undefined,
active: false
}
];
return new Promise(function(resolve) {
window.asyncStorage.getItem(ICE_CONTACTS_KEY, function(data) {
if (data) {
if (data[0]) {
iceContactsIds[0] = data[0];
}
if (data[1]) {
iceContactsIds[1] = data[1];
}
}
localIceContacts = iceContactsIds;
resolve(localIceContacts);
});
});
}
/**
* Set the value of an ICE contact, both in local and in the
* datastore
* @param id (string) contact id
* @param pos (int) current position (0,1)
* @param active (boolean) ice contact is active or not
*/
function setICEContact(id, pos, active) {
active = active || false;
Cache.evict();
// Save locally
localIceContacts[pos] = {
id: id,
active: active
};
return setIceContactsItem(localIceContacts).then(() => {
// Save in the datastore
return modifyICEInDS();
});
}
/**
* Set the values for ICE contacts, both in local and in the
* datastore
* @param iceContactList the list with ids of ICE Contacts to be set
*/
function setICEContacts(iceContactList) {
if (!Array.isArray(iceContactList)) {
return Promise.resolve();
}
// Save locally
localIceContacts = [
{
id: iceContactList[0],
active: !!iceContactList[0]
},
{
id: iceContactList[1],
active: !!iceContactList
}
];
return setIceContactsItem(localIceContacts).then(() => {
// Save in the datastore
return modifyICEInDS();
});
}
/**
* Clone the current local ice contacts into the datastore,
* considering the active flag.
* @return (Promise) fullfill when data saved in DS
*/
function modifyICEInDS() {
var contacts = [];
localIceContacts.forEach(function(iceContact) {
if (iceContact.id && iceContact.active) {
contacts.push(iceContact.id);
}
});
return ICEStore.setContacts(contacts);
}
/**
* Given a specific contact id removes it from the
* ice list, if present or disabled
* @param id (String) contact id
* @return (Promise) fullfill when data modified in DS
*/
function removeICEContact(id) {
var contact = localIceContacts.find(function(x) {
return x.id === id;
});
if (!contact) {
return Promise.resolve();
}
return new Promise(function(resolve, reject) {
var index = localIceContacts.indexOf(contact);
localIceContacts[index].id = null;
localIceContacts[index].active = false;
setIceContactsItem(localIceContacts).then(function() {
return modifyICEInDS().then(() => {
notifyCallbacks(localIceContacts);
});
}).then(resolve, reject);
});
}
function setIceContactsItem(iceContactsList) {
return new Promise(function(resolve, reject) {
window.asyncStorage.setItem(ICE_CONTACTS_KEY, iceContactsList,
resolve, reject);
});
}
/**
* Adds an observer to be called when an ice contact
* changed. We can add multiple listeners, since we will
* need to react in several parts of the app to this changes.
* Also the listener removes a contact id in case we are performing
* a delete. In case of modification we don't do anythying as we
* store just ids.
* Listener will be attached just once, but we can keep adding
* callbacks.
* @param fn (Function) callback to call when ice contact change
*/
function listenForChanges(fn) {
return new Promise(function(resolve) {
if (!onChangeAttached) {
load().then(function() {
document.addEventListener('contactChanged', onChangeEvent);
onChangeAttached = true;
});
}
if (typeof fn === 'function') {
onChangeCallbacks.push(fn);
}
resolve();
});
}
function notifyCallbacks(data) {
onChangeCallbacks.forEach(function(fn) {
fn(data);
});
}
function handleChangeEvent(evt) {
// Figure out if we got a change in a ICE contact
var contact = localIceContacts.find(function(x) {
return x.id === evt.detail.contactID;
});
if (!contact) {
return Promise.resolve();
}
// If it's a delete update all the storages
if (evt.detail.reason === 'remove') {
return removeICEContact(contact.id);
} else {
notifyCallbacks(localIceContacts);
return Promise.resolve();
}
}
function onChangeEvent(evt) {
// We should refresh the iceContacts before determining if it is necessary
// to notify or not
pendingChanges.push(evt);
if (!performingChange) {
performChange();
}
}
// We perform any change sequentially to avoid any race condition while
// saving to disc the ICE state.
function performChange() {
performingChange = true;
var evt = pendingChanges.pop();
if (!evt) {
performingChange = false;
return;
}
function callback() {
handleChangeEvent(evt).then(performChange);
}
load().then(callback, callback);
}
function getActiveIceContacts() {
return new Promise(function(resolve, reject) {
load().then(function() {
var result = [];
localIceContacts.forEach(function(aContact) {
if (aContact.active && aContact.id) {
result.push(aContact.id);
}
resolve(result);
});
}, reject);
});
}
function stopListenForChanges() {
document.removeEventListener('contactChanged', onChangeEvent);
onChangeCallbacks = [];
onChangeAttached = false;
}
exports.ICEData = {
load: load,
setICEContact: setICEContact,
setICEContacts: setICEContacts,
removeICEContact: removeICEContact,
get iceContacts() { return localIceContacts; },
getActiveIceContacts: getActiveIceContacts,
listenForChanges: listenForChanges,
stopListenForChanges: stopListenForChanges
};
})(window);