Browse Source

Firebase improvement

Real syncronization
pull/116/head
Ramiro Saenz 9 years ago
parent
commit
8eaf380517
  1. 14
      app.js
  2. 9
      app/Application.js
  3. 6
      app/model/Service.js
  4. 10
      app/profile/Offline.js
  5. 12
      app/profile/Online.js
  6. 56
      app/store/Services.js
  7. 107
      app/ux/Firebase.js
  8. 18
      app/view/main/Main.js
  9. 185
      app/view/main/MainController.js

14
app.js

@ -22,20 +22,6 @@ Ext.application({
,autoCreateViewport: 'Rambox.view.main.Main'
});
// Syncronize with Firebase
function sync() {
// Is not logged, Skip
if ( !localStorage.getItem('id_token') ) return;
var services = [];
Ext.getStore('Services').each(function(service) {
services.push(service.data);
});
fireRef.database().ref('users/' + Ext.decode(localStorage.getItem('profile')).user_id).set({
services: services
});
}
require('electron').ipcRenderer.on('showAbout', function(event, message) {
!Ext.cq1('about') ? Ext.create('Rambox.view.main.About') : '';
});

9
app/Application.js

@ -3,11 +3,20 @@ Ext.define('Rambox.Application', {
,name: 'Rambox'
,requires: [
'Rambox.ux.Firebase'
]
,stores: [
'ServicesList'
,'Services'
]
,profiles: [
'Offline'
,'Online'
]
,config: {
totalServicesLoaded: 0
,totalNotifications: 0

6
app/model/Service.js

@ -13,9 +13,6 @@ Ext.define('Rambox.model.Service', {
},{
name: 'position'
,type: 'int'
,convert: function( value, record ) {
return value ? value : Ext.getStore('Services').getCount() + 1;
}
},{
name: 'type'
,type: 'string'
@ -44,5 +41,8 @@ Ext.define('Rambox.model.Service', {
name: 'js_unread'
,type: 'string'
,defaultValue: ''
},{
name: 'firebase_key'
,type: 'int'
}]
});

10
app/profile/Offline.js

@ -0,0 +1,10 @@
Ext.define('Rambox.profile.Offline', {
extend: 'Ext.app.Profile'
,isActive: function() {
return !localStorage.getItem('id_token');
}
,launch: function() {
console.warn('USER NOT LOGGED IN');
}
});

12
app/profile/Online.js

@ -0,0 +1,12 @@
Ext.define('Rambox.profile.Online', {
extend: 'Ext.app.Profile'
,isActive: function() {
return localStorage.getItem('id_token');
}
,launch: function() {
console.info('USER LOGGED IN');
Rambox.ux.Firebase.createEvents(false);
}
});

56
app/store/Services.js

@ -20,10 +20,7 @@ Ext.define('Rambox.store.Services', {
,listeners: {
load: function( store, records, successful ) {
if ( Ext.isEmpty(records) ) {
Ext.cq1('app-main').add({ tabConfig : { xtype : 'tbfill' } });
return;
}
Ext.cq1('app-main').suspendEvent('add');
var servicesLeft = [];
var servicesRight = [];
@ -45,21 +42,56 @@ Ext.define('Rambox.store.Services', {
service.get('align') === 'left' ? servicesLeft.push(cfg) : servicesRight.push(cfg);
});
Ext.cq1('app-main').add(servicesLeft);
Ext.cq1('app-main').add({ tabConfig : { xtype : 'tbfill' } });
if ( !Ext.isEmpty(servicesLeft) ) Ext.cq1('app-main').insert(1, servicesLeft);
if ( !Ext.isEmpty(servicesRight) ) Ext.cq1('app-main').add(servicesRight);
if ( !Ext.isEmpty(servicesRight) ) {
Ext.cq1('app-main').add(servicesRight);
}
store.suspendEvent('load');
Ext.cq1('app-main').resumeEvent('add');
}
,add: function(store, records, index) {
sync();
var record = records[0];
if ( !localStorage.getItem('id_token') || (!Ext.isEmpty(record.previousValues) && !Ext.isEmpty(record.previousValues.position)) ) return true;
console.info('Saving into Firebase...', record.data);
var ref = fireRef.database().ref('test/' + Ext.decode(localStorage.getItem('profile')).user_id).child('services');
ref.once('value', function(snap) {
// Generate Key
var i = 0;
while ( snap.child(i).exists() ) { i++; }
// Save Firebase Key into record
record.set('firebase_key', i);
// Prevent saving local ID and Firebase Key into Firebase
var data = Ext.clone(record.data);
delete data.id;
delete data.firebase_key;
// Make the call
ref.child(i).set(data);
});
}
,update: function(store, record, operation, data) {
if ( operation === 'edit' ) sync();
// Is not logged, Skip
if ( !localStorage.getItem('id_token') || operation === 'commit' ) return;
if ( operation === 'edit' && data[0] !== 'firebase_key' ) {
var obj = {};
Ext.each(data, function(prop) {
obj[prop] = record.get(prop);
});
fireRef.database().ref('test/' + Ext.decode(localStorage.getItem('profile')).user_id + '/services').child(record.get('firebase_key')).update(obj);
}
}
,remove: function(store, records, index, isMove) {
sync();
if ( !localStorage.getItem('id_token') ) return;
Ext.each(records, function(rec) {
fireRef.database().ref('test/' + Ext.decode(localStorage.getItem('profile')).user_id).child('services').child(rec.get('firebase_key')).remove();
});
}
}
});

107
app/ux/Firebase.js

@ -0,0 +1,107 @@
Ext.define('Rambox.ux.Firebase', {
singleton: true
// private
,eventsDefined: false
,createEvents: function(createTabs) {
if ( this.eventsDefined || !localStorage.getItem('id_token') ) return;
console.log('Define listeners for Firebase');
var ref = fireRef.database().ref('test/' + Ext.decode(localStorage.getItem('profile')).user_id).child('services');
// Attach an asynchronous callback to read the data at our posts reference
ref.on("child_changed", function(snapshot, prevChildKey) {
console.info('Firebase - Child Changed', snapshot.val(), snapshot.key, prevChildKey);
Ext.getStore('Services').suspendEvent('update');
var rec = Ext.getStore('Services').findRecord('firebase_key', snapshot.key);
Ext.getCmp('tab_'+rec.get('id')).setTitle(snapshot.val().name);
if ( rec.get('position') !== snapshot.val().position ) {
var pos = parseInt(snapshot.val().position);
if ( rec.get('align') === 'right' ) pos++;
Ext.cq1('app-main').move(Ext.getCmp('tab_'+rec.get('id')), pos);
}
rec.set(snapshot.val());
rec.save();
Ext.getStore('Services').resumeEvent('update');
Ext.getStore('Services').load();
}, function (errorObject) {
});
ref.on("child_added", function(snapshot, prevChildKey) {
console.info('Firebase - Child Added', snapshot.val(), snapshot.key, prevChildKey);
Ext.getStore('Services').suspendEvents(['add', 'update']);
var rec = Ext.getStore('Services').findRecord('firebase_key', snapshot.key);
// Update current services
if ( rec ) {
rec.set(snapshot.val());
rec.save();
} else { // Add new ones if exist
var data = snapshot.val();
data.firebase_key = snapshot.key;
rec = Ext.create('Rambox.model.Service', data);
rec.save();
Ext.getStore('Services').add(rec);
var tabData = {
xtype: 'webview'
,id: 'tab_'+rec.get('id')
,title: rec.get('name')
,icon: rec.get('type') !== 'custom' ? 'resources/icons/'+rec.get('logo') : ( rec.get('logo') === '' ? 'resources/icons/custom.png' : rec.get('logo'))
,src: rec.get('url')
,type: rec.get('type')
,align: rec.get('align')
,notifications: rec.get('notifications')
,muted: rec.get('muted')
,record: rec
,tabConfig: {
service: rec
}
};
if ( rec.get('align') === 'left' ) {
var tbfill = Ext.cq1('app-main').getTabBar().down('tbfill');
Ext.cq1('app-main').insert(Ext.cq1('app-main').getTabBar().items.indexOf(tbfill), tabData);
} else {
Ext.cq1('app-main').add(tabData);
}
}
Ext.getStore('Services').resumeEvents(['add', 'update']);
Ext.getStore('Services').load();
//rec.commit();
}, function (errorObject) {
});
ref.on("child_removed", function(snapshot) {
console.info('Firebase - Child Removed', snapshot.val(), snapshot.key);
var rec = Ext.getStore('Services').findRecord('firebase_key', snapshot.key);
// Remove record from localStorage
if ( rec ) {
Ext.getStore('Services').suspendEvent('remove');
Ext.getStore('Services').remove(rec);
Ext.cq1('app-main').suspendEvent('remove');
Ext.getCmp('tab_'+rec.get('id')).close();
Ext.cq1('app-main').resumeEvent('remove');
Ext.getStore('Services').resumeEvent('remove');
Ext.getStore('Services').load();
}
}, function (errorObject) {
});
this.eventsDefined = true;
}
});

18
app/view/main/Main.js

@ -18,20 +18,6 @@ Ext.define('Rambox.view.main.Main', {
,plugins: [
{
ptype: 'tabreorderer'
,listeners: {
// I put the code here because it cannot be listened into the Controller
Drop: function( box, tabBar, tab, startIdx, index ) {
var idx = 0;
Ext.each(tabBar.items.items, function(t) {
if ( idx > 0 && t.xtype !== 'tbfill' ) { // Skip first tab because is the configuration tab
t.card.record.set('position', idx);
} else if ( t.xtype === 'tbfill' ) {
idx--;
}
idx++;
});
}
}
}
]
@ -41,6 +27,7 @@ Ext.define('Rambox.view.main.Main', {
,items: [
{
icon: 'resources/[email protected]'
,id: 'ramboxTab'
,closable: false
,reorderable: false
,autoScroll: true
@ -290,5 +277,8 @@ Ext.define('Rambox.view.main.Main', {
,listeners: {
tabchange: 'onTabChange'
,add: 'updatePositions'
,remove: 'updatePositions'
,childmove: 'updatePositions'
}
});

185
app/view/main/MainController.js

@ -1,9 +1,6 @@
Ext.define('Rambox.view.main.MainController', {
extend: 'Ext.app.ViewController'
,requires: [
]
,alias: 'controller.main'
// Make focus on webview every time the user change tabs, to enable the autofocus in websites
@ -14,6 +11,26 @@ Ext.define('Rambox.view.main.MainController', {
if ( webview ) webview.focus();
}
,updatePositions: function(tabPanel, tab) {
if ( tab.id === 'ramboxTab' || tab.id === 'tbfill' ) return true;
console.log('Updating Tabs positions...');
var store = Ext.getStore('Services');
store.suspendEvent('remove');
Ext.each(tabPanel.items.items, function(t, i) {
if ( t.id !== 'ramboxTab' && t.id !== 'tbfill' ) {
if ( t.record.get('align') === 'right' ) i--;
var rec = store.getById(t.record.get('id'));
rec.set('position', i);
rec.save();
}
});
store.load();
store.resumeEvent('remove');
}
,showSimpleModal: function(record, edit) {
var me = this;
@ -76,10 +93,10 @@ Ext.define('Rambox.view.main.MainController', {
}
,{
xtype: 'container'
,hidden: record.get('note') === ''
,data: { note: record.get('note') }
,hidden: (edit ? Ext.getStore('ServicesList').getById(record.get('type')).get('note') === '' : record.get('note') === '')
,data: { note: (edit ? Ext.getStore('ServicesList').getById(record.get('type')).get('note') : record.get('note')) }
,margin: '10 0 0 0'
,style: 'background-color:#93CFE0;color:#053767;'
,style: 'background-color:#93CFE0;color:#053767;border-radius:6px;'
,tpl: [
'<i class="fa fa-info-circle" aria-hidden="true" style="font-size:40px;margin:20px;"></i>'
,'<span style="font-size: 15px;position: absolute;padding: 10px 10px 10px 0;">{note}</span>'
@ -122,7 +139,6 @@ Ext.define('Rambox.view.main.MainController', {
,align: formValues.align
,notifications: formValues.notifications
,muted: formValues.muted
,js_unread: record.get('js_unread')
});
service.save();
Ext.getStore('Services').add(service);
@ -131,7 +147,7 @@ Ext.define('Rambox.view.main.MainController', {
xtype: 'webview'
,id: 'tab_'+service.get('id')
,title: service.get('name')
,icon: 'resources/icons/'+record.get('logo')
,icon: 'resources/icons/'+service.get('logo')
,src: service.get('url')
,type: service.get('type')
,align: formValues.align
@ -201,6 +217,7 @@ Ext.define('Rambox.view.main.MainController', {
,submitEmptyText: false
,emptyText: record.get('url') === '___' ? 'http://' : ''
,vtype: record.get('url') === '___' ? 'url' : ''
,width: 220
,listeners: {
specialkey: function(field, e) {
if(e.getKey() == e.ENTER && field.up('form').isValid()) {
@ -247,10 +264,10 @@ Ext.define('Rambox.view.main.MainController', {
}
,{
xtype: 'container'
,hidden: record.get('note') === ''
,data: { note: record.get('note') }
,hidden: (edit ? Ext.getStore('ServicesList').getById(record.get('type')).get('note') === '' : record.get('note') === '')
,data: { note: (edit ? Ext.getStore('ServicesList').getById(record.get('type')).get('note') : record.get('note')) }
,margin: '10 0 0 0'
,style: 'background-color:#93CFE0;color:#053767;'
,style: 'background-color:#93CFE0;color:#053767;border-radius:6px;'
,tpl: [
'<i class="fa fa-info-circle" aria-hidden="true" style="font-size:40px;margin:20px;"></i>'
,'<span style="font-size: 15px;position: absolute;padding: 10px 10px 10px 0;">{note}</span>'
@ -293,7 +310,6 @@ Ext.define('Rambox.view.main.MainController', {
,align: formValues.align
,notifications: formValues.notifications
,muted: formValues.muted
,js_unread: record.get('js_unread')
});
service.save();
Ext.getStore('Services').add(service);
@ -302,7 +318,7 @@ Ext.define('Rambox.view.main.MainController', {
xtype: 'webview'
,id: 'tab_'+service.get('id')
,title: service.get('name')
,icon: 'resources/icons/'+record.get('logo')
,icon: 'resources/icons/'+service.get('logo')
,src: service.get('url')
,type: service.get('type')
,align: formValues.align
@ -352,11 +368,11 @@ Ext.define('Rambox.view.main.MainController', {
tab.down('component').el.dom.getWebContents().session.clearCache(Ext.emptyFn);
tab.down('component').el.dom.getWebContents().session.clearStorageData({}, Ext.emptyFn);
// Close tab
tab.close();
// Remove record from localStorage
Ext.getStore('Services').remove(Ext.getStore('Services').getById(serviceId));
// Close tab
tab.close();
}
,removeService: function( gridView, rowIndex, colIndex, col, e, rec, rowEl ) {
@ -376,17 +392,23 @@ Ext.define('Rambox.view.main.MainController', {
if ( btn ) {
Ext.Msg.confirm('Please confirm...', 'Are you sure you want to remove all services?', function(btnId) {
if ( btnId === 'yes' ) {
Ext.cq1('app-main').suspendEvent('remove');
Ext.Array.each(Ext.getStore('Services').collect('id'), function(serviceId) {
me.removeServiceFn(serviceId);
});
Ext.getStore('Services').load();
if ( Ext.isFunction(callback) ) callback();
Ext.cq1('app-main').resumeEvent('remove');
}
});
} else {
Ext.cq1('app-main').suspendEvent('remove');
Ext.Array.each(Ext.getStore('Services').collect('id'), function(serviceId) {
me.removeServiceFn(serviceId);
});
Ext.getStore('Services').load();
if ( Ext.isFunction(callback) ) callback();
Ext.cq1('app-main').resumeEvent('remove');
}
}
@ -564,7 +586,7 @@ Ext.define('Rambox.view.main.MainController', {
xtype: 'webview'
,id: 'tab_'+service.get('id')
,title: service.get('name')
,icon: formValues.logo
,icon: 'resources/icons/'+service.get('logo')
,src: service.get('url')
,type: service.get('type')
,align: formValues.align
@ -745,7 +767,8 @@ Ext.define('Rambox.view.main.MainController', {
icon: 'resources/Icon.png'
}, function(err, profile, id_token) {
// There was an error logging the user in
if (err) return console.error(err);
//if (err) return console.error(err);
console.log('LOGIN', err, profile, id_token);
// Display a spinner while waiting
Ext.Msg.wait('Please wait until we get your configuration.', 'Connecting...');
@ -763,62 +786,80 @@ Ext.define('Rambox.view.main.MainController', {
if ( !err ) {
// Exchange the delegate token for a Firebase auth token
firebase.auth().signInWithCustomToken(result.id_token).then(function(snapshot) {
fireRef.database().ref('users/' + profile.user_id).once('value').then(function(snapshot) {
me.removeAllServices(false, function() {
if ( snapshot.val() === null || Ext.isEmpty(snapshot.val().services) ) return;
fireRef.database().ref('test/' + profile.user_id).child('services').orderByChild('position').once('value', function(snapshot2) {
Ext.Msg.hide();
Ext.each(snapshot.val().services, function(s) {
var service = Ext.create('Rambox.model.Service', {
id: s.id
,position: s.position
,type: s.type
,logo: s.logo
,name: s.name
,url: s.url
,align: s.align
,notifications: s.notifications
,muted: s.muted
,js_unread: s.js_unread
});
// Import Services function
var importServices = function(snap) {
snap.forEach(function(data) {
var s = data.val();
s.firebase_key = data.key;
var service = Ext.create('Rambox.model.Service', s);
service.save();
Ext.getStore('Services').add(service);
});
Ext.getStore('Services').resumeEvent('load');
Ext.getStore('Services').load();
var tabData = {
xtype: 'webview'
,id: 'tab_'+service.get('id')
,title: service.get('name')
,icon: 'resources/icons/' + s.logo
,src: service.get('url')
,type: service.get('type')
,align: s.align
,notifications: s.notifications
,muted: s.muted
,record: service
,tabConfig: {
service: service
// User is logged in
// Save the profile and JWT.
localStorage.setItem('profile', JSON.stringify(profile));
localStorage.setItem('id_token', id_token);
Rambox.ux.Firebase.createEvents();
}
};
if ( s.align === 'left' ) {
var tbfill = Ext.cq1('app-main').getTabBar().down('tbfill');
Ext.cq1('app-main').insert(Ext.cq1('app-main').getTabBar().items.indexOf(tbfill), tabData);
// Firebase empty and Have Services
if ( !snapshot2.hasChildren() && Ext.getStore('Services').getCount() > 0 ) {
Ext.Msg.confirm('Import', 'You don\'t have any service saved. Do you want to import your current services?', function(btnId) {
if ( btnId === 'yes' ) {
var services = [];
Ext.getStore('Services').each(function(service, index) {
service.set('firebase_key', index);
// Prevent saving local ID into Firebase
var data = Ext.clone(service.data);
delete data.id;
services.push(data);
});
fireRef.database().ref('test/' + profile.user_id).set({
services: services
});
// User is logged in
// Save the profile and JWT.
localStorage.setItem('profile', JSON.stringify(profile));
localStorage.setItem('id_token', id_token);
Rambox.ux.Firebase.createEvents();
} else {
Ext.Msg.confirm('Clear services', 'Do you want to remove all your current services to start over?<br /><br />If <b>NO</b>, you will be logged out.', function(btnId) {
if ( btnId === 'yes' ) {
me.removeAllServices(false);
} else {
Ext.cq1('app-main').add(tabData);
me.logout();
}
});
Ext.Msg.hide();
}
});
// Firebase not empty and Have Services
} else if ( snapshot2.hasChildren() && Ext.getStore('Services').getCount() > 0 ) {
Ext.Msg.confirm('Confirm', 'To import your configuration, I need to remove all your current services. Do you want to continue?<br /><br />If <b>NO</b>, you will be logged out.', function(btnId) {
if ( btnId === 'yes' ) {
me.removeAllServices(false, function() {
importServices(snapshot2);
});
} else {
me.logout();
}
});
// Firebase not empty and Have no Services
} else if ( snapshot2.hasChildren() && Ext.getStore('Services').getCount() === 0 ) {
importServices(snapshot2);
}
});
});
}
});
// User is logged in
// Save the profile and JWT.
localStorage.setItem('profile', JSON.stringify(profile));
localStorage.setItem('id_token', id_token);
Ext.cq1('app-main').getViewModel().set('username', profile.name);
Ext.cq1('app-main').getViewModel().set('avatar', profile.picture);
}, function() {
@ -829,22 +870,34 @@ Ext.define('Rambox.view.main.MainController', {
,logout: function(btn) {
var me = this;
Ext.Msg.confirm('Logout', 'Are you sure you want to logout?', function(btnId) {
if ( btnId === 'yes' ) {
var logoutFn = function(callback) {
Ext.Msg.wait('Closing you session...', 'Logout');
firebase.auth().signOut().then(function() {
localStorage.removeItem('profile');
localStorage.removeItem('id_token');
Ext.cq1('app-main').getViewModel().set('username', '');
Ext.cq1('app-main').getViewModel().set('avatar', '');
firebase.auth().signOut().then(function() {
Ext.Array.each(Ext.getStore('Services').collect('id'), function(serviceId) {
me.removeServiceFn(serviceId);
});
if ( Ext.isFunction(callback) ) callback();
Ext.Msg.hide();
}, function(error) {
console.error(error);
});
}
})
if ( btn ) {
Ext.Msg.confirm('Logout', 'Are you sure you want to logout?', function(btnId) {
if ( btnId === 'yes' ) {
logoutFn(function() {
me.removeAllServices();
});
}
});
} else {
logoutFn();
}
}
});

Loading…
Cancel
Save