From 5358965c463c97f2b9cddede1ed8fbce5690151b Mon Sep 17 00:00:00 2001 From: Allen Hancock Date: Wed, 9 Nov 2016 13:59:01 -0600 Subject: [PATCH 01/12] sets a mac-friendly name for auto-launch --- electron/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/main.js b/electron/main.js index a261020d..32ffdb0f 100644 --- a/electron/main.js +++ b/electron/main.js @@ -44,7 +44,7 @@ const config = new Config({ // Configure AutoLaunch const appLauncher = new AutoLaunch({ - name: 'Rambox' + name: 'Rambox.app' ,isHiddenOnLaunch: config.get('start_minimized') }); config.get('auto_launch') && !isDev ? appLauncher.enable() : appLauncher.disable(); From 3ecb7ff2645ad88c50f421bb13f7f475c65b3163 Mon Sep 17 00:00:00 2001 From: toC Date: Sat, 12 Nov 2016 02:54:46 +0900 Subject: [PATCH 02/12] remove extra space before service name --- app/store/ServicesList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/store/ServicesList.js b/app/store/ServicesList.js index 4047e9b1..ebb0656a 100644 --- a/app/store/ServicesList.js +++ b/app/store/ServicesList.js @@ -459,7 +459,7 @@ Ext.define('Rambox.store.ServicesList', { ,type: 'email' }, { - id: ' irccloud' + id: 'irccloud' ,logo: 'irccloud.png' ,name: 'IRCCloud' ,description: 'IRCCloud is a modern IRC client that keeps you connected, with none of the baggage.' From f523ac407fbc9e3afb4fdbbff29de7e9b9324af8 Mon Sep 17 00:00:00 2001 From: PotHix Date: Mon, 21 Nov 2016 13:56:30 -0200 Subject: [PATCH 03/12] Do not count Telegram muted chats. Instead of reporting muted chats, it will just count the ones that are not muted. --- app/store/ServicesList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/store/ServicesList.js b/app/store/ServicesList.js index 4047e9b1..c8f81c16 100644 --- a/app/store/ServicesList.js +++ b/app/store/ServicesList.js @@ -95,7 +95,7 @@ Ext.define('Rambox.store.ServicesList', { ,url: 'https://web.telegram.org/' ,type: 'messaging' ,titleBlink: true - ,js_unread: 'function checkUnread(){var e=document.getElementsByClassName("im_dialog_badge badge"),t=0;for(i=0;i Date: Tue, 22 Nov 2016 09:02:43 +0100 Subject: [PATCH 04/12] Increases scrolling steps and adds scrolling animations to the tab bar. #424 --- .../layout/container/boxOverflow/Scroller.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 overrides/layout/container/boxOverflow/Scroller.js diff --git a/overrides/layout/container/boxOverflow/Scroller.js b/overrides/layout/container/boxOverflow/Scroller.js new file mode 100644 index 00000000..69682125 --- /dev/null +++ b/overrides/layout/container/boxOverflow/Scroller.js @@ -0,0 +1,34 @@ +/** + * Per default scrolling the tab bar moves the tabs 20 pixels. + * To improve the usability of the tab bar this value is increased for Rambox. + * Also animations are enabled, so the user understands what's going on. + */ +Ext.define('Rambox.overrides.layout.container.boxOverflow.Scroller', { + override: 'Ext.layout.container.boxOverflow.Scroller', + + scrollIncrement: 250, + wheelIncrement: 50, + + animateScroll: true, + scrollDuration: 250, + + /** + * In difference to the overridden function this one enables scroll animations. + * + * @private + * Scrolls to the left by the configured amount + */ + scrollLeft: function() { + this.scrollBy(-this.scrollIncrement); + }, + + /** + * In difference to the overridden function this one enables scroll animations. + * + * @private + * Scrolls to the right by the configured amount + */ + scrollRight: function() { + this.scrollBy(this.scrollIncrement); + } +}); From 8d12b608582aaa302a8b1b6d1e2f3a499a23a194 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Fri, 25 Nov 2016 22:05:12 +0100 Subject: [PATCH 05/12] Adds options to disable the unread count for a service per tab or globally --- app/model/Service.js | 13 +++- app/store/Services.js | 6 +- app/util/Notifier.js | 57 ++++++++++++++++ app/util/UnreadCounter.js | 76 ++++++++++++++++++++++ app/ux/WebView.js | 118 ++++++++++++++++++++-------------- app/view/add/Add.js | 27 +++++++- app/view/add/AddController.js | 46 ++++++++----- 7 files changed, 274 insertions(+), 69 deletions(-) create mode 100644 app/util/Notifier.js create mode 100644 app/util/UnreadCounter.js diff --git a/app/model/Service.js b/app/model/Service.js index 41eb4de2..fe35526b 100644 --- a/app/model/Service.js +++ b/app/model/Service.js @@ -37,7 +37,18 @@ Ext.define('Rambox.model.Service', { name: 'muted' ,type: 'boolean' ,defaultValue: false - },{ + }, + { + name: 'displayTabUnreadCounter', + type: 'boolean', + defaultValue: true + }, + { + name: 'includeInGlobalUnreadCounter', + type: 'boolean', + defaultValue: true + }, + { name: 'trust' ,type: 'boolean' ,defaultValue: false diff --git a/app/store/Services.js b/app/store/Services.js index 81a2f441..62eeae81 100644 --- a/app/store/Services.js +++ b/app/store/Services.js @@ -33,8 +33,10 @@ Ext.define('Rambox.store.Services', { ,icon: service.get('type') !== 'custom' ? 'resources/icons/'+service.get('logo') : ( service.get('logo') === '' ? 'resources/icons/custom.png' : service.get('logo')) ,src: service.get('url') ,type: service.get('type') - ,muted: service.get('muted') - ,enabled: service.get('enabled') + ,muted: service.get('muted'), + includeInGlobalUnreadCounter: service.get('includeInGlobalUnreadCounter'), + displayTabUnreadCounter: service.get('displayTabUnreadCounter'), + enabled: service.get('enabled') ,record: service ,tabConfig: { service: service diff --git a/app/util/Notifier.js b/app/util/Notifier.js new file mode 100644 index 00000000..5d0da406 --- /dev/null +++ b/app/util/Notifier.js @@ -0,0 +1,57 @@ + +/** + * Singleton class for notification dispatching. + */ +Ext.define('Rambox.util.Notifier', { + + singleton: true, + + constructor: function(config) { + + config = config || {}; + + /** + * Returns the notification text depending on the service type. + * + * @param view + * @param count + * @return {*} + */ + function getNotificationText(view, count) { + var text; + switch (Ext.getStore('ServicesList').getById(view.type).get('type')) { + case 'messaging': + text = 'You have ' + Ext.util.Format.plural(count, 'new message', 'new messages') + '.'; + break; + case 'email': + text = 'You have ' + Ext.util.Format.plural(count, 'new email', 'new emails') + '.'; + break; + default: + text = 'You have ' + Ext.util.Format.plural(count, 'new activity', 'new activities') + '.'; + break; + } + return text; + } + + /** + * Dispatches a notification for a specific service. + * + * @param view The view of the service + * @param {number} count The unread count + */ + this.dispatchNotification = function(view, count) { + var text = getNotificationText(view, count); + + var notification = new Notification(view.record.get('name'), { + body: text, + icon: view.tab.icon, + silent: view.record.get('muted') + }); + + notification.onclick = function() { + require('electron').remote.getCurrentWindow().show(); + Ext.cq1('app-main').setActiveTab(view); + }; + } + } +}); diff --git a/app/util/UnreadCounter.js b/app/util/UnreadCounter.js new file mode 100644 index 00000000..d6f98fca --- /dev/null +++ b/app/util/UnreadCounter.js @@ -0,0 +1,76 @@ +/** + * Singleton class to handle the global unread counter. + */ +Ext.define('Rambox.util.UnreadCounter', { + + singleton: true, + + constructor: function(config) { + + config = config || {}; + + /** + * Map for storing the global unread count. + * service id -> unread count + * + * @type {Map} + */ + var unreadCountByService = new Map(); + + /** + * Holds the global unread count for internal usage. + * + * @type {number} + */ + var totalUnreadCount = 0; + + /** + * Sets the application's unread count to tracked unread count. + */ + function updateAppUnreadCounter() { + Rambox.app.setTotalNotifications(totalUnreadCount); + } + + /** + * Returns the global unread count. + * + * @return {number} + */ + this.getTotalUnreadCount = function() { + return totalUnreadCount; + }; + + /** + * Sets the global unread count for a specific service. + * + * @param {*} id Id of the service to set the global unread count for. + * @param {number} unreadCount The global unread count for the service. + */ + this.setUnreadCountForService = function(id, unreadCount) { + unreadCount = parseInt(unreadCount, 10); + + console.log('Rambox.util.UnreadCounter#setUnreadCountForService(' + id + ', ' + unreadCount + ')'); + if (unreadCountByService.has(id)) { + totalUnreadCount -= unreadCountByService.get(id); + } + totalUnreadCount += unreadCount; + unreadCountByService.set(id, unreadCount); + + updateAppUnreadCounter(); + }; + + /** + * Clears the global unread count for a specific service. + * + * @param {*} id Id of the service to clear the global unread count for. + */ + this.clearUnreadCountForService = function(id) { + if (unreadCountByService.has(id)) { + totalUnreadCount -= unreadCountByService.get(id); + } + unreadCountByService['delete'](id); + + updateAppUnreadCounter(); + } + } +}); diff --git a/app/ux/WebView.js b/app/ux/WebView.js index e681b331..053b8bc1 100644 --- a/app/ux/WebView.js +++ b/app/ux/WebView.js @@ -6,14 +6,17 @@ Ext.define('Rambox.ux.WebView',{ ,xtype: 'webview' ,requires: [ - 'Rambox.util.Format' - ] + 'Rambox.util.Format', + 'Rambox.util.Notifier', + 'Rambox.util.UnreadCounter' + ], // private - ,zoomLevel: 0 + zoomLevel: 0, + currentUnreadCount: 0, // CONFIG - ,hideMode: 'offsets' + hideMode: 'offsets' ,initComponent: function(config) { var me = this; @@ -44,8 +47,7 @@ Ext.define('Rambox.ux.WebView',{ ,muted: me.record.get('muted') ,tabConfig: { listeners: { - badgetextchange: me.onBadgeTextChange - ,afterrender : function( btn ) { + afterrender : function( btn ) { btn.el.on('contextmenu', function(e) { btn.showMenu('contextmenu'); e.stopEvent(); @@ -168,42 +170,6 @@ Ext.define('Rambox.ux.WebView',{ return cfg; } - ,onBadgeTextChange: function( tab, badgeText, oldBadgeText ) { - var me = this; - if ( oldBadgeText === null ) oldBadgeText = 0; - var actualNotifications = Rambox.app.getTotalNotifications(); - - oldBadgeText = Rambox.util.Format.stripNumber(oldBadgeText); - badgeText = Rambox.util.Format.stripNumber(badgeText); - - Rambox.app.setTotalNotifications(actualNotifications - oldBadgeText + badgeText); - - // Some services dont have Desktop Notifications, so we add that functionality =) - if ( Ext.getStore('ServicesList').getById(me.type).get('manual_notifications') && oldBadgeText < badgeText && me.record.get('notifications') && !JSON.parse(localStorage.getItem('dontDisturb')) ) { - var text; - switch ( Ext.getStore('ServicesList').getById(me.type).get('type') ) { - case 'messaging': - text = 'You have ' + Ext.util.Format.plural(badgeText, 'new message', 'new messages') + '.'; - break; - case 'email': - text = 'You have ' + Ext.util.Format.plural(badgeText, 'new email', 'new emails') + '.'; - break; - default: - text = 'You have ' + Ext.util.Format.plural(badgeText, 'new activity', 'new activities') + '.'; - break; - } - var not = new Notification(me.record.get('name'), { - body: text - ,icon: tab.icon - ,silent: me.record.get('muted') - }); - not.onclick = function() { - require('electron').remote.getCurrentWindow().show(); - Ext.cq1('app-main').setActiveTab(me); - }; - } - } - ,onAfterRender: function() { var me = this; @@ -302,20 +268,77 @@ Ext.define('Rambox.ux.WebView',{ count = count === '•' ? count : Ext.isArray(count.match(/\d+/g)) ? count.match(/\d+/g).join("") : count.match(/\d+/g); // Some services have special characters. Example: (•) count = count === null ? '0' : count; - me.tab.setBadgeText(Rambox.util.Format.formatNumber(count)); + me.setUnreadCount(count); }); webview.addEventListener('did-get-redirect-request', function( e ) { if ( e.isMainFrame ) webview.loadURL(e.newURL); }); - } + }, - ,reloadService: function(btn) { + setUnreadCount: function(newUnreadCount) { + var me = this; + + if (me.record.get('includeInGlobalUnreadCounter') === true) { + Rambox.util.UnreadCounter.setUnreadCountForService(me.record.get('id'), newUnreadCount); + } else { + Rambox.util.UnreadCounter.clearUnreadCountForService(me.record.get('id')); + } + + me.setTabBadgeText(Rambox.util.Format.formatNumber(newUnreadCount)); + + /** + * Dispatch manual notification if + * • service doesn't have notifications, so Rambox does them + * • count increased + * • not in dnd mode + * • notifications enabled + */ + if (Ext.getStore('ServicesList').getById(me.type).get('manual_notifications') && + me.currentUnreadCount < newUnreadCount && + me.record.get('notifications') && + !JSON.parse(localStorage.getItem('dontDisturb'))) { + Rambox.util.Notifier.dispatchNotification(me, newUnreadCount); + } + + me.currentUnreadCount = newUnreadCount; + }, + + refreshUnreadCount: function() { + this.setUnreadCount(this.currentUnreadCount); + }, + + /** + * Sets the tab badge text depending on the service config param "displayTabUnreadCounter". + * + * @param {string} badgeText + */ + setTabBadgeText: function(badgeText) { + var me = this; + if (me.record.get('displayTabUnreadCounter') === true) { + me.tab.setBadgeText(badgeText); + } else { + me.tab.setBadgeText(''); + } + }, + + /** + * Clears the unread counter for this view: + * • clears the badge text + * • clears the global unread counter + */ + clearUnreadCounter: function() { + var me = this; + me.tab.setBadgeText(''); + Rambox.util.UnreadCounter.clearUnreadCountForService(me.record.get('id')); + }, + + reloadService: function(btn) { var me = this; var webview = me.down('component').el.dom; if ( me.record.get('enabled') ) { - me.tab.setBadgeText(''); + me.clearUnreadCounter(); webview.loadURL(me.src); } } @@ -361,7 +384,8 @@ Ext.define('Rambox.ux.WebView',{ ,setEnabled: function(enabled) { var me = this; - me.tab.setBadgeText(''); + me.clearUnreadCounter(); + me.removeAll(); me.add(me.webViewConstructor(enabled)); if ( enabled ) { diff --git a/app/view/add/Add.js b/app/view/add/Add.js index 8e32e81f..26790f9b 100644 --- a/app/view/add/Add.js +++ b/app/view/add/Add.js @@ -162,8 +162,31 @@ Ext.define('Rambox.view.add.Add',{ ,inputValue: true } ] - } - ,{ + }, + { + xtype: 'fieldset', + title: 'Unread counter', + margin: '10 0 0 0', + items: [ + { + xtype: 'checkbox', + boxLabel: 'Display tab unread counter', + name: 'displayTabUnreadCounter', + checked: me.edit ? me.record.get('displayTabUnreadCounter') : true, + uncheckedValue: false, + inputValue: true + }, + { + xtype: 'checkbox', + boxLabel: 'Include in global unread counter', + name: 'includeInGlobalUnreadCounter', + checked: me.edit ? me.record.get('includeInGlobalUnreadCounter') : true, + uncheckedValue: false, + inputValue: true + } + ] + }, + { xtype: 'fieldset' ,title: 'Advanced' ,margin: '10 0 0 0' diff --git a/app/view/add/AddController.js b/app/view/add/AddController.js index 97ce0a73..5c4e6cbb 100644 --- a/app/view/add/AddController.js +++ b/app/view/add/AddController.js @@ -1,8 +1,12 @@ Ext.define('Rambox.view.add.AddController', { - extend: 'Ext.app.ViewController' - ,alias: 'controller.add-add' + extend: 'Ext.app.ViewController', + alias: 'controller.add-add', - ,doCancel: function( btn ) { + requires: [ + 'Rambox.util.UnreadCounter' + ], + + doCancel: function( btn ) { var me = this; me.getView().close(); @@ -29,37 +33,44 @@ Ext.define('Rambox.view.add.AddController', { ,url: formValues.url ,align: formValues.align ,notifications: formValues.notifications - ,muted: formValues.muted - ,trust: formValues.trust + ,muted: formValues.muted, + displayTabUnreadCounter: formValues.displayTabUnreadCounter, + includeInGlobalUnreadCounter: formValues.includeInGlobalUnreadCounter, + trust: formValues.trust ,js_unread: formValues.js_unread }); + + var view = Ext.getCmp('tab_'+win.record.get('id')); + // Change the title of the Tab - Ext.getCmp('tab_'+win.record.get('id')).setTitle(formValues.serviceName); + view.setTitle(formValues.serviceName); // Change sound of the Tab - Ext.getCmp('tab_'+win.record.get('id')).setAudioMuted(formValues.muted); + view.setAudioMuted(formValues.muted); // Change notifications of the Tab - Ext.getCmp('tab_'+win.record.get('id')).setNotifications(formValues.notifications); + view.setNotifications(formValues.notifications); // Change the icon of the Tab if ( win.record.get('type') === 'custom' && oldData.logo !== formValues.logo ) Ext.getCmp('tab_'+win.record.get('id')).setConfig('icon', formValues.logo === '' ? 'resources/icons/custom.png' : formValues.logo); // Change the URL of the Tab - if ( oldData.url !== formValues.url ) Ext.getCmp('tab_'+win.record.get('id')).setURL(formValues.url); + if ( oldData.url !== formValues.url ) view.setURL(formValues.url); // Change the align of the Tab if ( oldData.align !== formValues.align ) { if ( formValues.align === 'left' ) { - Ext.cq1('app-main').moveBefore(Ext.getCmp('tab_'+win.record.get('id')), Ext.getCmp('tbfill')); + Ext.cq1('app-main').moveBefore(view, Ext.getCmp('tbfill')); } else { - Ext.cq1('app-main').moveAfter(Ext.getCmp('tab_'+win.record.get('id')), Ext.getCmp('tbfill')); + Ext.cq1('app-main').moveAfter(view, Ext.getCmp('tbfill')); } } // Apply the JS Code of the Tab if ( win.down('textarea').isDirty() ) { Ext.Msg.confirm('CUSTOM CODE', 'Rambox needs to reload the service to execute the new JavaScript code. Do you want to do it now?', function( btnId ) { - if ( btnId === 'yes' ) Ext.getCmp('tab_'+win.record.get('id')).reloadService(); + if ( btnId === 'yes' ) view.reloadService(); }); } - Ext.getCmp('tab_'+win.record.get('id')).record = win.record; - Ext.getCmp('tab_'+win.record.get('id')).tabConfig.service = win.record; + view.record = win.record; + view.tabConfig.service = win.record; + + view.refreshUnreadCount(); } else { // Format data if ( win.record.get('url').indexOf('___') >= 0 ) { @@ -73,8 +84,10 @@ Ext.define('Rambox.view.add.AddController', { ,url: formValues.url ,align: formValues.align ,notifications: formValues.notifications - ,muted: formValues.muted - ,trust: formValues.trust + ,muted: formValues.muted, + displayTabUnreadCounter: formValues.displayTabUnreadCounter, + includeInGlobalUnreadCounter: formValues.includeInGlobalUnreadCounter, + trust: formValues.trust ,js_unread: formValues.js_unread }); service.save(); @@ -121,5 +134,4 @@ Ext.define('Rambox.view.add.AddController', { // Make focus to the name field win.down('textfield[name="serviceName"]').focus(true, 100); } - }); From 6fe04d05fd9505e8f0ad2dd57dc9e8e972c749c4 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Fri, 25 Nov 2016 22:06:14 +0100 Subject: [PATCH 06/12] Removes debug logging --- app/util/UnreadCounter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/util/UnreadCounter.js b/app/util/UnreadCounter.js index d6f98fca..46617b0f 100644 --- a/app/util/UnreadCounter.js +++ b/app/util/UnreadCounter.js @@ -49,7 +49,6 @@ Ext.define('Rambox.util.UnreadCounter', { this.setUnreadCountForService = function(id, unreadCount) { unreadCount = parseInt(unreadCount, 10); - console.log('Rambox.util.UnreadCounter#setUnreadCountForService(' + id + ', ' + unreadCount + ')'); if (unreadCountByService.has(id)) { totalUnreadCount -= unreadCountByService.get(id); } From bcfaa413f029d7a27284d79699dae7f300f4f479 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Sat, 26 Nov 2016 13:09:27 +0100 Subject: [PATCH 07/12] Adds an option to control the behavior on closing the main window --- app/view/preferences/Preferences.js | 33 +++++++++++++++++++---------- electron/main.js | 21 ++++++++++++------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/app/view/preferences/Preferences.js b/app/view/preferences/Preferences.js index 749340a1..f24d77dc 100644 --- a/app/view/preferences/Preferences.js +++ b/app/view/preferences/Preferences.js @@ -67,17 +67,28 @@ Ext.define('Rambox.view.preferences.Preferences',{ ,boxLabel: 'Show in Taskbar' ,value: config.skip_taskbar ,reference: 'skipTaskbar' - ,hidden: process.platform !== 'win32' - } - ,{ - xtype: 'checkbox' - ,name: 'keep_in_taskbar_on_close' - ,boxLabel: 'Keep Rambox in the Taskbar when close it' - ,value: config.keep_in_taskbar_on_close - ,bind: { disabled: '{!skipTaskbar.checked}' } - ,hidden: process.platform !== 'win32' - } - ,{ + ,hidden: process.platform === 'darwin' + }, + { + xtype: 'combo', + name: 'window_close_behavior', + fieldLabel: 'When closing the main window', + labelAlign: 'top', + value: config.window_close_behavior, + displayField: 'label', + valueField: 'value', + editable: false, + store: Ext.create('Ext.data.Store', { + fields: ['value', 'label'], + data : [ + { 'value': 'keep_in_tray', 'label': 'Keep in tray' }, + { 'value': 'keep_in_tray_and_taskbar', 'label': 'Keep in tray and taskbar' }, + { 'value': 'quit', 'label': 'Quit' } + ] + }), + hidden: process.platform === 'darwin' + }, + { xtype: 'checkbox' ,name: 'always_on_top' ,boxLabel: 'Always on top' diff --git a/electron/main.js b/electron/main.js index a261020d..a43a008e 100644 --- a/electron/main.js +++ b/electron/main.js @@ -23,10 +23,9 @@ const config = new Config({ always_on_top: false ,hide_menu_bar: false ,skip_taskbar: true - ,auto_launch: !isDev - // On Linux false because it's uncommon for apps on linux to stay in the taskbar on close - ,keep_in_taskbar_on_close: process.platform !== 'linux' - ,start_minimized: false + ,auto_launch: !isDev, + window_close_behavior: 'keep_in_tray', + start_minimized: false ,systemtray_indicator: true ,master_password: false ,disable_gpu: process.platform === 'linux' @@ -199,11 +198,19 @@ function createWindow () { app.hide(); break; case 'linux': - config.get('keep_in_taskbar_on_close') ? mainWindow.hide() : app.quit(); - break; case 'win32': default: - config.get('keep_in_taskbar_on_close') ? mainWindow.minimize() : mainWindow.hide(); + switch (config.get('window_close_behavior')) { + case 'keep_in_tray': + mainWindow.hide(); + break; + case 'keep_in_tray_and_taskbar': + mainWindow.minimize(); + break; + case 'quit': + app.quit(); + break; + } break; } } From f26d183d438898894f2ab2f49e08e70da45f16b9 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Sat, 26 Nov 2016 13:59:36 +0100 Subject: [PATCH 08/12] Fixes ctrl + tab cycling --- app/Application.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Application.js b/app/Application.js index 43fdc2b3..806924db 100644 --- a/app/Application.js +++ b/app/Application.js @@ -44,9 +44,14 @@ Ext.define('Rambox.Application', { var tabPanel = Ext.cq1('app-main'); var activeIndex = tabPanel.items.indexOf(tabPanel.getActiveTab()); var i = activeIndex + 1; - if ( i >= tabPanel.items.items.length - 1 ) i = 0; - while ( tabPanel.items.items[i].id === 'tbfill' ) i++; - tabPanel.setActiveTab( i ); + + // "cycle" (go to the start) when the end is reached or the end is the spacer "tbfill" + if (i === tabPanel.items.items.length || i === tabPanel.items.items.length - 1 && tabPanel.items.items[i].id === 'tbfill') i = 0; + + // skip spacer + while (tabPanel.items.items[i].id === 'tbfill') i++; + + tabPanel.setActiveTab(i); } } ,{ From 84217ca865a176bf9dbb94527ce0ef8dee623ed7 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Sat, 26 Nov 2016 14:33:44 +0100 Subject: [PATCH 09/12] Fixes preferences master password handling --- app/view/preferences/PreferencesController.js | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/app/view/preferences/PreferencesController.js b/app/view/preferences/PreferencesController.js index b635e075..c90e9aec 100644 --- a/app/view/preferences/PreferencesController.js +++ b/app/view/preferences/PreferencesController.js @@ -13,12 +13,28 @@ Ext.define('Rambox.view.preferences.PreferencesController', { var values = me.getView().down('form').getForm().getFieldValues(); - // Master Password - if ( values.master_password && (Ext.isEmpty(values.master_password1) || Ext.isEmpty(values.master_password2)) ) return; - if ( values.master_password && (values.master_password1 !== values.master_password2) ) return; - if ( values.master_password ) values.master_password = Rambox.util.MD5.encypt(values.master_password1); - delete values.master_password1; - delete values.master_password2; + // master password activated and only one of the fields "password" or "password confirmation" filled + if (values.master_password === true && + (Ext.isEmpty(values.master_password1) === false && Ext.isEmpty(values.master_password2) === true || + Ext.isEmpty(values.master_password1) === true && Ext.isEmpty(values.master_password2) === false)) return; + + // password and confirmation don't match + if (values.master_password === true && (values.master_password1 !== values.master_password2)) return; + + // master password activated and changed + if (values.master_password === true && + Ext.isEmpty(values.master_password1) === false && + Ext.isEmpty(values.master_password2) === false) { + + values.master_password = Rambox.util.MD5.encypt(values.master_password1); + delete values.master_password1; + delete values.master_password2; + } + + // prevent overwriting password when unchanged + if (values.master_password === true) { + delete values.master_password; + } // Proxy if ( values.proxy && (Ext.isEmpty(values.proxyHost) || Ext.isEmpty(values.proxyPort)) ) return; From 920cf6c73687d5cbb67b0d3462479ed307a31466 Mon Sep 17 00:00:00 2001 From: Atao Date: Tue, 20 Dec 2016 14:55:39 +0100 Subject: [PATCH 10/12] Add facebook at work (workplace) --- app/store/ServicesList.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/store/ServicesList.js b/app/store/ServicesList.js index 4047e9b1..febc85ca 100644 --- a/app/store/ServicesList.js +++ b/app/store/ServicesList.js @@ -660,6 +660,14 @@ Ext.define('Rambox.store.ServicesList', { ,description: 'Unified multi-channel messaging for businesses, bots and software makers.' ,url: 'https://app.smooch.io/' ,type: 'messaging' + }, + { + id: 'Workplace' + ,logo: 'workplace.png' + ,name: 'Workplace by Facebook' + ,description: 'Connect everyone in your company and turn ideas into action. Through group discussion, a personalised News Feed, and voice and video calling, work together and get more done. Workplace is an ad-free space, separate from your personal Facebook account.' + ,url: 'https://___.facebook.com/' + ,type: 'messaging' } ] }); From fbf80f82341e28f2fbf74f48203611b48630d852 Mon Sep 17 00:00:00 2001 From: Atao Date: Tue, 20 Dec 2016 14:57:16 +0100 Subject: [PATCH 11/12] Add facebook for work icon --- resources/icons/workplace.png | Bin 0 -> 3269 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/icons/workplace.png diff --git a/resources/icons/workplace.png b/resources/icons/workplace.png new file mode 100644 index 0000000000000000000000000000000000000000..8f40205023c8ab1a73f518f2d9f45613b7f259ee GIT binary patch literal 3269 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 literal 0 HcmV?d00001 From a9fa8999b6c50278f46f39e66754b8116b331d2b Mon Sep 17 00:00:00 2001 From: Ramiro Saenz Date: Sun, 15 Jan 2017 21:02:05 -0300 Subject: [PATCH 12/12] New backer --- Backers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Backers.md b/Backers.md index bff2e750..485bd372 100644 --- a/Backers.md +++ b/Backers.md @@ -3,3 +3,4 @@ [Martin Grünbaum](https://github.com/alathon) Ivan Toshkov +[Simon Joda Stößer](https://github.com/SimJoSt)