diff --git a/app/controllers/default-controller.js b/app/controllers/default-controller.js new file mode 100644 index 0000000..b24b1fa --- /dev/null +++ b/app/controllers/default-controller.js @@ -0,0 +1,7 @@ +let angApp = require(__dirname+'/../init') + +angApp.controller('DefaultController', function($scope, ChimeVerseService) { + + console.log('always-test') + +}); \ No newline at end of file diff --git a/app/controllers/login-controller.js b/app/controllers/login-controller.js new file mode 100644 index 0000000..1a5a98b --- /dev/null +++ b/app/controllers/login-controller.js @@ -0,0 +1,11 @@ +let angApp = require(__dirname+'/../init') + +angApp.controller('LoginController', function($scope, ChimeVerseService, SettingsServise) { + $scope.addAccountAndLoginAction = () => { + SettingsServise.addCredentials($scope.bosh, + $scope.login, + $scope.password + ) + ChimeVerseService.initConverse($scope.bosh, $scope.login, $scope.password) + } +}); \ No newline at end of file diff --git a/app/controllers/settings-controller.js b/app/controllers/settings-controller.js new file mode 100644 index 0000000..4121336 --- /dev/null +++ b/app/controllers/settings-controller.js @@ -0,0 +1,6 @@ + +let angApp = require(__dirname+'/../init') + +angApp.controller('SettingsController', function ($scope, ChimeVerseService) { + +}) \ No newline at end of file diff --git a/app/init.js b/app/init.js new file mode 100644 index 0000000..95a6c9c --- /dev/null +++ b/app/init.js @@ -0,0 +1,4 @@ +const angular = require('angular') +let angApp = angular.module('app', []) + +module.exports = angApp \ No newline at end of file diff --git a/app/services/app-state-service.js b/app/services/app-state-service.js new file mode 100644 index 0000000..5bb8f51 --- /dev/null +++ b/app/services/app-state-service.js @@ -0,0 +1,19 @@ +let angApp = require(__dirname + '/../init') + +angApp.factory('AppStateService', [ '$rootScope', ($rootScope) => { + + let stateService = {} + + stateService.APP_STATE_LOGIN = 'login' + stateService.APP_STATE_DEFAULT = 'default' + stateService.APP_STATE_SETTINGS = 'settings' + + stateService.set = (state) => { + stateService.state = state + $rootScope.$broadcast('app:state:changed', stateService.state); + } + + stateService.set(stateService.APP_STATE_DEFAULT) + + return stateService +}]) \ No newline at end of file diff --git a/app/services/chimeverse-service.js b/app/services/chimeverse-service.js new file mode 100644 index 0000000..0d6cad3 --- /dev/null +++ b/app/services/chimeverse-service.js @@ -0,0 +1,60 @@ +let angApp = require(__dirname + '/../init') + +angApp.factory('ChimeVerseService', ($window, SettingsServise, SystemService, AppStateService) => { + + let chimeverseService = {} + + chimeverseService._notifyMessage = () => { + SystemService.playAudio() + SystemService.showEnvelope() + } + + chimeverseService._hideNotifyMessage = () => { + SystemService.hideEnvelope() + } + + chimeverseService.logout = () => { + let credentials = SettingsServise.getCredentials() + credentials.then((result) => { + let remove = SettingsServise.removeCredentials(result.login) + console.log('Remove credential on logout') + remove.then(() => { + console.log('Switch to the login state') + AppStateService.set(AppStateService.APP_STATE_LOGIN) + }) + }) + } + + chimeverseService.initConverse = (bosh, login, password) => { + AppStateService.set(AppStateService.APP_STATE_DEFAULT) // Always set to default state before init + let lang = navigator.language + converse.initialize({ + allow_bookmarks: false, + bosh_service_url: bosh, + view_mode: 'embedded', + jid: login + '/chimeverse', + password: password, + auto_login: true, + whitelisted_plugins: ['chimeVerse'], + i18n: lang, + priority: 50, + // debug: true, + auto_reconnect: true + }) + } + + $window.document.addEventListener('conversejs-logout', function (e) { + chimeverseService.logout() + }); + + $window.document.addEventListener('conversejs-unread', function (e) { + chimeverseService._notifyMessage() + }); + + $window.document.addEventListener('conversejs-no-unread', function (e) { + chimeverseService._hideNotifyMessage() + }); + + return chimeverseService + +}) \ No newline at end of file diff --git a/app/services/settings-service.js b/app/services/settings-service.js new file mode 100644 index 0000000..dbd0deb --- /dev/null +++ b/app/services/settings-service.js @@ -0,0 +1,54 @@ +let angApp = require(__dirname+'/../init') + +angApp.factory('SettingsServise', () => { + + const keytar = require('keytar') + const settings = require('electron-settings') + + let settingsService = {} + + settingsService.getCredentials = () => { + let credentials = {} + credentials.login = settings.get('login') + let promise = new Promise((resolve, reject) => { + if (credentials.login) { + credentials.bosh = settings.get('bosh') + credentials.xmppService = credentials.login.split('@').pop() + let password = keytar.getPassword(credentials.xmppService, credentials.login) + password.then((result) => { + credentials.password = result + resolve(credentials) + }) + } + else { + reject(Error('No login stored')) + } + }) + return promise + } + + settingsService.addCredentials = (bosh, login, password) => { + let xmppService = login.split('@').pop() + settings.set('bosh', bosh) + settings.set('login', login) + keytar.setPassword(xmppService, login, password) + } + + settingsService.removeCredentials = (login) => { + let xmppService = login.split('@').pop() + passwordDelete = keytar.deletePassword(xmppService, login) + let promise = new Promise((resolve, reject) => { + passwordDelete.then((result) => { + settings.delete('login') + settings.delete('bosh') + resolve() + }, (error) => { + reject(error) + }) + }) + return promise + } + + return settingsService +}) + diff --git a/app/services/system-service.js b/app/services/system-service.js new file mode 100644 index 0000000..92e1e85 --- /dev/null +++ b/app/services/system-service.js @@ -0,0 +1,28 @@ +let angApp = require(__dirname + '/../init') + +angApp.factory('SystemService', () => { + + const remote = require('electron').remote + + let systemService = {} + + systemService.playAudio = () => { + var audio = new Audio(__dirname + '/sounds/graceful.ogg') + audio.play() + } + + systemService.showEnvelope = () => { + remote.require('./main').trayService.showEnvelope() + } + + systemService.hideEnvelope = () => { + remote.require('./main').trayService.hideEnvelope() + } + + systemService.reloadWindow = () => { + remote.getCurrentWindow().reload() + } + + return systemService + +}) \ No newline at end of file diff --git a/app/views/default/page.html b/app/views/default/page.html new file mode 100644 index 0000000..f4e27ee --- /dev/null +++ b/app/views/default/page.html @@ -0,0 +1,10 @@ +
+
+ +

Chimeverse

+
v0.1.52
+
+
+
+
+
\ No newline at end of file diff --git a/css/app.css b/css/app.css deleted file mode 100644 index a256837..0000000 --- a/css/app.css +++ /dev/null @@ -1,11 +0,0 @@ -.ng-cloak { - display: none !important; -} - -.noselect { - -webkit-touch-callout: none; /* iOS Safari */ - -webkit-user-select: none; /* Safari */ - -khtml-user-select: none; /* Konqueror HTML */ - user-select: none; /* Non-prefixed version, currently - supported by Chrome and Opera */ -} diff --git a/index.html b/index.html index 9d6c527..e59e873 100644 --- a/index.html +++ b/index.html @@ -1,84 +1,75 @@ - - - Chimeverse - - - - - -
- -
-
-
-

Welcome to Chimeverse

-
Jabber/XMPP client based on Converse.js and Electron
-
-
-
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- -
-
- Credentials stored via Keychain -
-
-
-
+ + + + Chimeverse + + + + + + + +
+
+
+ +
+
+
+
+
+ +
-
-
- - -
-
- -

Chimeverse

-
v0.0.16
+
+
+ +
+
+
+ + +
+
+
+ +
+
+ Credentials stored via Keychain +
+
+
+ settings +
+
- - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/libs/converse.js/3rdparty/chimeverse-plugin.js b/libs/converse.js/3rdparty/chimeverse-plugin.js new file mode 100644 index 0000000..3b79fa9 --- /dev/null +++ b/libs/converse.js/3rdparty/chimeverse-plugin.js @@ -0,0 +1,36 @@ +let chimeversePlugin = {} + +chimeversePlugin.register = () => { + converse.plugins.add('chimeVerse', { + initialize: (event) => { + let _converse = event.properties._converse + Promise.all([ + _converse.api.waitUntil('rosterContactsFetched'), + _converse.api.waitUntil('chatBoxesFetched') + ]).then(() => { + _converse.api.listen.on('logout', () => { + let event = new CustomEvent("conversejs-logout") + document.dispatchEvent(event) + }) + _converse.api.listen.on('message', (data) => { + let event = new CustomEvent("conversejs-unread") + document.dispatchEvent(event) + //chimeverseService._notifyMessage(data) + }) + _converse.api.listen.on('chatBoxFocused', () => { + let event = new CustomEvent("conversejs-no-unread") + document.dispatchEvent(event) + //chimeverseService._hideNotifyMessage() + }) + window.document.addEventListener('converse-force-logout', function (e) { + console.log('Get converse-force-logout event') + console.log('Logout form plugin') + _converse.api.user.logout(); + //chimeverseService.logout() + }); + }) + } + }) +} + +module.exports = chimeversePlugin \ No newline at end of file diff --git a/main.js b/main.js index fa3c896..490d151 100644 --- a/main.js +++ b/main.js @@ -33,7 +33,7 @@ function createWindow () { menuService.createMenu() // Open the DevTools. - // mainWindow.webContents.openDevTools() + mainWindow.webContents.openDevTools() // Emitted when the window is closed. mainWindow.on('closed', function () { diff --git a/modules/tray-service.js b/modules/tray-service.js index 2491270..f5c47fa 100644 --- a/modules/tray-service.js +++ b/modules/tray-service.js @@ -11,7 +11,7 @@ let trayService = {} trayService.initTray = (window) => { trayServiceWindow = window - let iconPath = __dirname + '/../images/icon.png' + let iconPath = __dirname + '/../resources/images/icon.png' tray = new Tray(iconPath) tray.setToolTip('Chimeverse') @@ -22,11 +22,11 @@ trayService.initTray = (window) => { } trayService.showEnvelope = () => { - tray.setImage(__dirname + '/../images/envelope.png') + tray.setImage(__dirname + '/../resources/images/envelope.png') } trayService.hideEnvelope = () => { - tray.setImage(__dirname + '/../images/icon.png') + tray.setImage(__dirname + '/../resources/images/icon.png') } module.exports = trayService diff --git a/package-lock.json b/package-lock.json index 9c13c8d..ffb010e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,11 +66,6 @@ "resolved": "https://registry.npmjs.org/angular/-/angular-1.7.9.tgz", "integrity": "sha512-5se7ZpcOtu0MBFlzGv5dsM1quQDoDeUTwZrWjGtTNA7O88cD8TEk5IEKCTDa3uECV9XnvKREVUr7du1ACiWGFQ==" }, - "angular-route": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.7.9.tgz", - "integrity": "sha512-vRoj5hzdQtWbODhWJqDzD1iNOEfCKshO6GFBuPVV7RHlPjzIc4R2dHCc7Qiv/8F3LDxJDohc6vSnTDMLHuaqeA==" - }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -3453,11 +3448,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "uikit": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/uikit/-/uikit-3.4.2.tgz", - "integrity": "sha512-z5NH1s8sTMHjVQ+Exr2IKgPn/bG9f5PSK4HcTZaBlw3mF6f5UgefWIA3xKVsOtOeJSOQ2T8lk++59syRF5NwOw==" - }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", diff --git a/package.json b/package.json index 0b6c0e8..254e3f7 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,9 @@ }, "dependencies": { "angular": "^1.7.9", - "angular-route": "^1.7.9", "converse.js": "^6.0.0", "electron-settings": "^3.2.0", "keytar": "^4.13.0", - "n": "^6.5.1", - "uikit": "^3.4.2" + "n": "^6.5.1" } } diff --git a/renderer.js b/renderer.js index 4bb1022..411d212 100644 --- a/renderer.js +++ b/renderer.js @@ -2,191 +2,46 @@ // be executed in the renderer process for that window. // All of the Node.js APIs are available in this process. -const angular = require('angular') +var angApp = require('./app/init') -var angApp = angular.module('app', []) +require('./app/services/settings-service') +require('./app/services/system-service') +require('./app/services/app-state-service') +require('./app/services/chimeverse-service') +require('./app/controllers/settings-controller') +require('./app/controllers/login-controller') +require('./app/controllers/default-controller') +const chimeversePlugin = require('./libs/converse.js/3rdparty/chimeverse-plugin') +chimeversePlugin.register() +angApp.controller('AppController', function ($scope, $timeout, ChimeVerseService, SettingsServise, AppStateService) { -angApp.factory('SettingsServise', () => { - - const keytar = require('keytar') - const settings = require('electron-settings') - - let settingsService = {} - - settingsService.getCredentials = () => { - let credentials = {} - credentials.login = settings.get('login') - let promise = new Promise((resolve, reject) => { - if (credentials.login) { - credentials.bosh = settings.get('bosh') - credentials.xmppService = credentials.login.split('@').pop() - let password = keytar.getPassword(credentials.xmppService, credentials.login) - password.then((result) => { - credentials.password = result - resolve(credentials) - }) - } - else { - reject(Error('No login stored')) - } - }) - return promise - } - - settingsService.addCredentials = (bosh, login, password) => { - let xmppService = login.split('@').pop() - settings.set('bosh', bosh) - settings.set('login', login) - keytar.setPassword(xmppService, login, password) - } - - settingsService.removeCredentials = (login) => { - let xmppService = login.split('@').pop() - passwordDelete = keytar.deletePassword(xmppService, login) - let promise = new Promise((resolve, reject) => { - passwordDelete.then((result) => { - settings.delete('login') - settings.delete('bosh') - resolve() - }, (error) => { - reject(error) - }) - }) - return promise - } - - return settingsService -}) - - -angApp.factory('SystemService', () => { - - const remote = require('electron').remote - - let systemService = {} - - systemService.playAudio = () => { - var audio = new Audio(__dirname + '/sounds/graceful.ogg') - audio.play() - } - - systemService.showEnvelope = () => { - remote.require('./main').trayService.showEnvelope() - } - - systemService.hideEnvelope = () => { - remote.require('./main').trayService.hideEnvelope() - } - - systemService.reloadWindow = () => { - remote.getCurrentWindow().reload() - } - - return systemService - -}) - - -angApp.factory('ChimeVerseService', (SettingsServise, SystemService) => { - - let chimeverseService = {} - - chimeverseService.settings = SettingsServise - chimeverseService.system = SystemService - - chimeverseService._notifyMessage = (data) => { - if (data.message.attributes.sender === 'me') { - chimeverseService.system.hideEnvelope() - return ; - } - if (data.message.attributes.chat_state === 'active') { - chimeverseService.system.playAudio() - chimeverseService.system.showEnvelope() - } - } - - chimeverseService.logout = () => { - let credentials = SettingsServise.getCredentials() - credentials.then((result) => { - let remove = chimeverseService.settings.removeCredentials(result.login) - remove.then(() => { - chimeverseService.system.reloadWindow() - }) - }) - } - - chimeverseService.addChimeVersePluign = () => { - converse.plugins.add('chimeVerse', { - initialize: (event) => { - var _converse = event.properties._converse - Promise.all([ - _converse.api.waitUntil('rosterContactsFetched'), - _converse.api.waitUntil('chatBoxesFetched') - ]).then(() => { - _converse.api.listen.on('logout', () => { - chimeverseService.logout() - }) - _converse.api.listen.on('messageAdded', (data) => { - chimeverseService._notifyMessage(data) - }) - _converse.api.listen.on('chatBoxFocused', () => { - chimeverseService.system.hideEnvelope() - }) - }) - } - }) - } - - chimeverseService.initConverse = (bosh, login, password) => { - chimeverseService.addChimeVersePluign() - let lang = navigator.language - converse.initialize({ - bosh_service_url: bosh, - view_mode: 'fullscreen', - jid: login + '/chimeverse', - password: password, - auto_login: true, - whitelisted_plugins: ['chimeVerse'], - i18n: lang, - priority: 50, - // debug: true, - auto_reconnect: true - }) - } - - return chimeverseService - -}) - - -angApp.controller('AppController', function ($scope, ChimeVerseService) { - + //const { remote, ipcRenderer } = require('electron') const { ipcRenderer } = require('electron') - $scope.showLoginForm = false - ipcRenderer.on('force-logout-event', () => { - ChimeVerseService.logout() - ipcRenderer.getCurrentWindow().reload() + let event = new CustomEvent("converse-force-logout") // Dispatch to the plugin + document.dispatchEvent(event) + //remote.getCurrentWindow().reload() }) - $scope.addAccountAction = () => { - ChimeVerseService.settings.addCredentials($scope.bosh, $scope.login, $scope.password) - $scope.showLoginForm = false - ChimeVerseService.initConverse($scope.bosh, $scope.login, $scope.password) - } + $scope.state = AppStateService.APP_STATE_DEFAULT + + $scope.$on('app:state:changed', (event, data) => { + // @see https://docs.angularjs.org/error/$rootScope/inprog + $timeout(() => { + $scope.state = data + console.log($scope.state) + }, 0) + }); $scope.getCredentialsAndLogin = () => { - let credentials = ChimeVerseService.settings.getCredentials() + let credentials = SettingsServise.getCredentials() credentials.then((result) => { ChimeVerseService.initConverse(result.bosh, result.login, result.password) }, (error) => { - $scope.showLoginForm = true - $scope.$apply() + AppStateService.set(AppStateService.APP_STATE_LOGIN) }) } - $scope.getCredentialsAndLogin() - }) diff --git a/resources/css/app.css b/resources/css/app.css new file mode 100644 index 0000000..305d7a1 --- /dev/null +++ b/resources/css/app.css @@ -0,0 +1,33 @@ +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +.noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + user-select: none; /* Non-prefixed version, currently + supported by Chrome and Opera */ +} + +body { + background: #f8f8f8; +} + +.main-background { + background: #f8f8f8; + height: 100%; + left: 0px; + position: fixed; + top: 0px; + width: 100%; + z-index: -1; +} + +.conversejs-adoption { + position: fixed; + left: 0px; + top: 0px; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/resources/css/page-default.css b/resources/css/page-default.css new file mode 100644 index 0000000..8c0d27c --- /dev/null +++ b/resources/css/page-default.css @@ -0,0 +1,6 @@ +.chimeverse-branding { + left: 50%; + position: absolute; + top: 50%; + width: 300px; +} \ No newline at end of file diff --git a/images/envelope.png b/resources/images/envelope.png similarity index 100% rename from images/envelope.png rename to resources/images/envelope.png diff --git a/images/envelope@2x.png b/resources/images/envelope@2x.png similarity index 100% rename from images/envelope@2x.png rename to resources/images/envelope@2x.png diff --git a/images/icon.png b/resources/images/icon.png similarity index 100% rename from images/icon.png rename to resources/images/icon.png diff --git a/images/icon@2x.png b/resources/images/icon@2x.png similarity index 100% rename from images/icon@2x.png rename to resources/images/icon@2x.png diff --git a/images/logo.icns b/resources/images/logo.icns similarity index 100% rename from images/logo.icns rename to resources/images/logo.icns diff --git a/images/logo.png b/resources/images/logo.png similarity index 100% rename from images/logo.png rename to resources/images/logo.png diff --git a/images/logo@2x.icns b/resources/images/logo@2x.icns similarity index 100% rename from images/logo@2x.icns rename to resources/images/logo@2x.icns diff --git a/images/logo@2x.png b/resources/images/logo@2x.png similarity index 100% rename from images/logo@2x.png rename to resources/images/logo@2x.png diff --git a/sounds/graceful.ogg b/resources/sounds/graceful.ogg similarity index 100% rename from sounds/graceful.ogg rename to resources/sounds/graceful.ogg