Compare commits
32 Commits
Author | SHA1 | Date |
---|---|---|
Keith Maika | d0bcd90f67 | |
Keith Maika | c016bab4b3 | |
Keith Maika | ff8eaa91ea | |
JC Brand | 3c52c0daff | |
JC Brand | cf822e54f8 | |
Keith Maika | adfdde2f20 | |
Keith Maika | 9436bb9802 | |
Keith Maika | 50c0978148 | |
Keith Maika | 2697d61ab1 | |
JC Brand | 5aad0dfe34 | |
JC Brand | 3f4aabf734 | |
JC Brand | cc565b5d1f | |
Keith Maika | 2740bac95b | |
JC Brand | 6b9910aa13 | |
Keith Maika | 6f5cc13b2e | |
Keith Maika | 933c853395 | |
Keith Maika | 702c174fb0 | |
Keith Maika | 7f7703b537 | |
Keith Maika | e38d68579d | |
Keith Maika | 4b6cf4b86a | |
Keith Maika | 4ce02148e2 | |
JC Brand | 1a62af799b | |
JC Brand | cc3dae61ad | |
Keith Maika | 4c6ce2e905 | |
Keith Maika | ff0bf695a8 | |
Keith Maika | 8f106c65ec | |
Keith Maika | a9d3f89f3f | |
Keith Maika | fb72aee403 | |
JC Brand | fce4f0af8e | |
Nick Denry | 58c73e367f | |
Nick Denry | 4111bb1050 | |
Nick Denry | fe46a0698a |
|
@ -0,0 +1,22 @@
|
|||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 13,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"globals": {
|
||||
"__dirname": true,
|
||||
"converse": true,
|
||||
"exports": true,
|
||||
"module": true,
|
||||
"process": true,
|
||||
"require": true,
|
||||
},
|
||||
"rules": {
|
||||
"prefer-const": "error",
|
||||
}
|
||||
};
|
|
@ -1,3 +1,4 @@
|
|||
node_modules
|
||||
.DS_*
|
||||
package-lock.json
|
||||
dist/
|
||||
.idea/
|
||||
|
|
12
CHANGES.md
|
@ -1,3 +1,15 @@
|
|||
## 9.1.0 (2022-04-07)
|
||||
|
||||
- Update to converse.js 9.1.0
|
||||
- Update to Electron to 18.0.1
|
||||
- Remove angularjs and simplify application
|
||||
|
||||
## 0.1.0 (2020-08-07)
|
||||
|
||||
- Fix error handling for version check
|
||||
- Relicensed under MPL-2.0 (@see libsignal-protocol.js exclusion at README section)
|
||||
- First release since forked from [Chimeverse project](https://github.com/nick-denry/Chimeverse)
|
||||
|
||||
## 0.0.1 (Unreleased)
|
||||
|
||||
- Forked from [Chimeverse](https://github.com/nick-denry/Chimeverse)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
BIN ?= ./node_modules/.bin/
|
||||
ESLINT ?= ./node_modules/.bin/eslint
|
||||
|
||||
clean:
|
||||
npm run clean
|
||||
|
||||
node_modules: package.json package-lock.json
|
||||
npm i
|
||||
|
||||
serve: node_modules
|
||||
npm start
|
||||
|
||||
dist: node_modules
|
||||
npm dist
|
||||
|
||||
.PHONY: eslint
|
||||
eslint: node_modules
|
||||
$(ESLINT) *.js
|
||||
$(ESLINT) app/**/*.js
|
96
README.md
|
@ -1,62 +1,88 @@
|
|||
<h2 style="text-align: center">
|
||||
<a href="https://conversejs.org" target="_blank" rel="noopener">
|
||||
<img alt="Converse-Desktop" src="https://github.com/conversejs/converse.js/blob/master/logo/readme.png" width="480">
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
# Converse Desktop
|
||||
|
||||
This project started as a fork of Nick Denry's [Chimeverse](https://github.com/conversejs/converse-desktop).
|
||||
## Jabber/XMPP client based on Converse.js and Electron
|
||||
|
||||
#### Jabber/XMPP client based on Converse.js and Electron
|
||||
[![XMPP Chat](https://conference.conversejs.org/muc_badge/discuss@conference.conversejs.org)](https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org)
|
||||
|
||||
![Version](https://img.shields.io/npm/v/chimeverse/latest.svg)
|
||||
![Downloads](https://img.shields.io/npm/dt/chimeverse.svg)
|
||||
![License](https://img.shields.io/npm/l/chimeverse.svg)
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MZ5YRYEDSVSQ&source=url" title="Donate once-off to this project using Paypal">
|
||||
<img src="https://img.shields.io/badge/paypal-donate-yellow.svg" alt="PayPayl donate button" />
|
||||
</a>
|
||||
A basic integration of [Converse.js](https://conversejs.org/) and Electron. With OMEMO.
|
||||
|
||||
It should happen once. A very basic integration of [Converse.js](https://conversejs.org/) and Electron. With OMEMO.
|
||||
## Screenshots and features
|
||||
|
||||
#### Screenshots and feautures
|
||||
<p float="left">
|
||||
<img width="403" alt="Account form" src="https://user-images.githubusercontent.com/1450983/89672948-33bc0e80-d8ee-11ea-983f-21bbb707b45d.png">
|
||||
<img width="403" alt="Main window" src="https://user-images.githubusercontent.com/1450983/89673019-4f271980-d8ee-11ea-8058-0ac6269983aa.png">
|
||||
<img width="403" alt="Chat" src="https://user-images.githubusercontent.com/1450983/89673064-68c86100-d8ee-11ea-86c4-137e1b95dae7.png">
|
||||
<img width="403" alt="Settings screen" src="https://user-images.githubusercontent.com/1450983/89673104-7847aa00-d8ee-11ea-8d30-8f84e7709e7c.png">
|
||||
[![Login screen](https://user-images.githubusercontent.com/6234547/161444310-ed1157fe-4f09-4334-b133-f16a8b1ead86.jpg)](https://user-images.githubusercontent.com/6234547/161444142-87008557-a0ae-414d-ab81-9740502dab30.jpg)
|
||||
[![One-to-one chat](https://user-images.githubusercontent.com/6234547/161444320-62179698-d4cb-4522-8ee4-5fd727bbff0d.jpg)](https://user-images.githubusercontent.com/6234547/161444152-8a44b284-48a6-4c8e-a16e-95399b4def16.jpg)
|
||||
[![Multi-user chat](https://user-images.githubusercontent.com/6234547/161444323-5fe7e478-1923-47c3-9e99-84020fb44009.jpg)](https://user-images.githubusercontent.com/6234547/161444156-eb2224a7-6082-4fe7-aa55-44eec093e04d.jpg)
|
||||
|
||||
</p>
|
||||
|
||||
- Permanent account storage
|
||||
- Tray icon
|
||||
- Tray notifications
|
||||
- All the best from Converse.js like system notifications, MAM, OMEMO etc. See details at [Converse.js](https://conversejs.org/)
|
||||
|
||||
#### Changelog
|
||||
|
||||
## Changelog
|
||||
|
||||
See [CHANGES.md](https://github.com/conversejs/converse-desktop/blob/master/CHANGES.md)
|
||||
|
||||
#### Run with npm
|
||||
|
||||
```
|
||||
#### Latest release installers
|
||||
|
||||
| Operation System | Download link |
|
||||
|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| macOS | [Converse_Desktop-9.1.0_x64.dmg](https://github.com/conversejs/converse-desktop/releases/download/v9.1.0/Converse.Desktop-9.1.0.dmg) |
|
||||
| Windows | [Converse_Desktop_Setup-9.1.0_x64.exe](https://github.com/conversejs/converse-desktop/releases/download/v9.1.0/Converse.Desktop.Setup.9.1.0.exe) |
|
||||
| Linux DEB | [converse_desktop-9.1.0_amd64.deb](https://github.com/conversejs/converse-desktop/releases/download/v9.1.0/converse_desktop-9.1.0_amd64.deb) |
|
||||
| Linux AppImage | [converse_desktop-9.1.0_x86_64.AppImage](https://github.com/conversejs/converse-desktop/releases/download/v9.1.0/converse_desktop-9.1.0_x86_64.AppImage) |
|
||||
| Linux other | [converse_desktop-9.1.0_x64.tar.gz](https://github.com/conversejs/converse-desktop/releases/download/v9.1.0/converse_desktop-9.1.0_x64.tar.gz) |
|
||||
|
||||
- [All releases](https://github.com/conversejs/converse-desktop/releases)
|
||||
|
||||
|
||||
## Build from source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/conversejs/converse-desktop.git
|
||||
cd converse-desktop
|
||||
npm i
|
||||
$(npm bin)/electron-rebuild
|
||||
```
|
||||
|
||||
Then, to run:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
### Development
|
||||
### Build targets:
|
||||
|
||||
Prepare
|
||||
```
|
||||
git clone https://github.com/conversejs/converse-desktop.git
|
||||
cd converse-desktop
|
||||
npm i
|
||||
$(npm bin)/electron-rebuild
|
||||
```
|
||||
|
||||
Build targets
|
||||
|
||||
| Operation System | Target |
|
||||
-------------------|----------------
|
||||
| macOS | `npm run dist` |
|
||||
| Windows | `npm run dist:win64` |
|
||||
| Linux DEB | `npm run dist:linux64deb` |
|
||||
| Operation System | Target |
|
||||
|------------------|------------------------|
|
||||
| macOS | `npm run dist` |
|
||||
| Windows | `npm run dist:win64` |
|
||||
| Linux | `npm run dist:linux64` |
|
||||
|
||||
More targets could be added via `package.json`. See [electron builder docs](https://www.electron.build/configuration/configuration).
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Like Converse.js, Converse Desktop's files are released under the Mozilla Public License version 2 (MPLv2). The gist of this license is that the covered files must stay open source, and modifications to them need to be released under the same license, but new files (for example for your own plugin) don't have to be released under the same license.
|
||||
|
||||
However, libsignal library, which is required for OMEMO support is released under the GPLv3. The MPLv2 license is compatible with GPLv3 and when GPLv3 code is included, the entire project effectively is licensed under the GPLv3.
|
||||
|
||||
Any custom build of Converse Desktop without libsignal included will again be licensed
|
||||
under the MPLv2.
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This project started as a fork of Nick Denry's [Chimeverse](https://github.com/conversejs/converse-desktop).
|
||||
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MZ5YRYEDSVSQ&source=url" title="Donate once-off to this project using Paypal">
|
||||
<img src="https://img.shields.io/badge/paypal-donate-yellow.svg" alt="PayPal donate button" />
|
||||
</a>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.controller('AboutController', function($scope, AppStateService, AppInfo) {
|
||||
|
||||
$scope.appInfo = AppInfo
|
||||
|
||||
$scope.closeAbout = () => {
|
||||
AppStateService.set(AppStateService.APP_STATE_DEFAULT)
|
||||
}
|
||||
})
|
|
@ -1,47 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.controller('DefaultController', function($scope, $timeout, $http, AppInfo) {
|
||||
|
||||
$scope.appInfo = AppInfo
|
||||
|
||||
let getUpdateInfo = () => {
|
||||
$http({
|
||||
url: $scope.appInfo.APP_RELEASES_CHECK_URL,
|
||||
method: 'GET'
|
||||
}).then((response) => {
|
||||
let releaseTag = response.data[0].tag_name
|
||||
let releaseVersion = parseInt(releaseTag.replace(/v|\./g, ''))
|
||||
let appVersion = parseInt($scope.appInfo.APP_VERSION.replace(/v|\./g, ''))
|
||||
if (appVersion < releaseVersion ) {
|
||||
$scope.checkingForUpdate = 'updateAvailable'
|
||||
}
|
||||
else {
|
||||
$scope.checkingForUpdate = 'latest'
|
||||
}
|
||||
}).catch((error) => {
|
||||
$scope.checkingForUpdate = 'checkErr'
|
||||
})
|
||||
}
|
||||
|
||||
let checkForUpdate = (timeout = 5000) => {
|
||||
$scope.checkingForUpdate = 'inProgress'
|
||||
$timeout(() => {
|
||||
getUpdateInfo()
|
||||
}, timeout)
|
||||
}
|
||||
|
||||
let checkForUpdateDelayed = (timeout = 5000) => {
|
||||
$timeout(() => {
|
||||
checkForUpdate()
|
||||
}, timeout)
|
||||
}
|
||||
|
||||
checkForUpdateDelayed()
|
||||
|
||||
$scope.checkRetry = ($event) => {
|
||||
$event.preventDefault()
|
||||
checkForUpdate()
|
||||
}
|
||||
|
||||
|
||||
})
|
|
@ -1,7 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.controller('FooterController', function($scope, AppInfo) {
|
||||
|
||||
$scope.appInfo = AppInfo
|
||||
|
||||
})
|
|
@ -1,21 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.controller('LoginController', function($scope, DesktopService, CredentialsServise) {
|
||||
|
||||
$scope.help = {}
|
||||
|
||||
$scope.showHelp = (item) => {
|
||||
$scope.help[item] = typeof $scope.help[item] === 'undefined' ? true : !$scope.help[item];
|
||||
}
|
||||
|
||||
$scope.addAccountAndLoginAction = () => {
|
||||
CredentialsServise.addCredentials($scope.credentials.connectionManager,
|
||||
$scope.credentials.login,
|
||||
$scope.credentials.password
|
||||
)
|
||||
DesktopService.getCredentialsAndLogin()
|
||||
$scope.accountForm.$setPristine()
|
||||
$scope.accountForm.$setUntouched()
|
||||
$scope.credentials = {}
|
||||
}
|
||||
})
|
|
@ -1,40 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.controller('SettingsController', function ($scope, $rootScope, AppStateService, SettingsService) {
|
||||
|
||||
let formInitialized = false
|
||||
$scope.settingsChanged = false
|
||||
$scope.settingsSaved = false
|
||||
|
||||
const settingsSetPristine = () => {
|
||||
$scope.settingsChanged = false
|
||||
formInitialized = false
|
||||
}
|
||||
|
||||
$scope.closeSettings = () => {
|
||||
$scope.settings = SettingsService.loadAll()
|
||||
settingsSetPristine()
|
||||
AppStateService.set(AppStateService.APP_STATE_DEFAULT)
|
||||
}
|
||||
|
||||
$scope.saveSettings = () => {
|
||||
$scope.settingsSaved = true
|
||||
SettingsService.saveAll($scope.settings)
|
||||
settingsSetPristine()
|
||||
}
|
||||
|
||||
$scope.restartApp = () => {
|
||||
$rootScope.$broadcast('app:restart')
|
||||
}
|
||||
|
||||
$scope.settings = SettingsService.loadAll()
|
||||
|
||||
$scope.$watch("settings", () => {
|
||||
if (!formInitialized) {
|
||||
formInitialized = true
|
||||
} else {
|
||||
$scope.settingsChanged = true
|
||||
}
|
||||
}, true)
|
||||
|
||||
})
|
|
@ -0,0 +1,25 @@
|
|||
const credentials = await import('../credentials.js');
|
||||
|
||||
converse.plugins.add('converse-desktop-credentials', {
|
||||
|
||||
initialize () {
|
||||
const { _converse } = this;
|
||||
const { api } = _converse;
|
||||
|
||||
api.listen.on('afterResourceBinding', () => {
|
||||
if (_converse.connection.pass) {
|
||||
credentials.addCredentials(
|
||||
_converse.connection.service,
|
||||
_converse.bare_jid,
|
||||
_converse.connection.pass
|
||||
).catch((reason) => {
|
||||
console.log(reason);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
api.listen.on('logout', () => {
|
||||
credentials.getCredentials().then((result) => credentials.removeCredentials(result.login))
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
/* global api */
|
||||
|
||||
converse.plugins.add('converse-desktop-trayicon', {
|
||||
|
||||
initialize () {
|
||||
const { _converse } = this;
|
||||
let envelopeIsShowing = false;
|
||||
|
||||
async function hideEnvelope () {
|
||||
if (envelopeIsShowing) {
|
||||
await api.trayService.hideEnvelope();
|
||||
envelopeIsShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('focus', hideEnvelope);
|
||||
_converse.api.listen.on('chatBoxInitialized', hideEnvelope);
|
||||
_converse.api.listen.on('chatBoxFocused', hideEnvelope);
|
||||
_converse.api.listen.on('messageNotification', async () => {
|
||||
await api.trayService.showEnvelope();
|
||||
envelopeIsShowing = true;
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
/* global api */
|
||||
|
||||
async function addCredentials (connectionManager, login, password) {
|
||||
const xmppService = login.split('@').pop()
|
||||
await api.settings.set('connectionManager', connectionManager)
|
||||
await api.settings.set('login', login)
|
||||
await api.keytar.setPassword(xmppService, login, password)
|
||||
}
|
||||
|
||||
async function getCredentials () {
|
||||
const credentials = {}
|
||||
credentials.login = (await api.settings.get('login')) || '';
|
||||
if (credentials.login) {
|
||||
credentials.connectionManager = await api.settings.get('connectionManager') || null
|
||||
credentials.xmppService = credentials.login.split('@').pop()
|
||||
credentials.password = await api.keytar.getPassword(credentials.xmppService, credentials.login)
|
||||
}
|
||||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
async function removeCredentials (login) {
|
||||
const xmppService = login.split('@').pop();
|
||||
await api.keytar.deletePassword(xmppService, login);
|
||||
await api.settings.unset('login');
|
||||
await api.settings.unset('connectionManager');
|
||||
}
|
||||
|
||||
export {
|
||||
addCredentials,
|
||||
getCredentials,
|
||||
removeCredentials
|
||||
}
|
12
app/init.js
|
@ -1,12 +0,0 @@
|
|||
const angular = require('angular')
|
||||
let angApp = angular.module('app', [])
|
||||
|
||||
angApp.constant('AppInfo', {
|
||||
APP_NAME: 'Converse Desktop',
|
||||
APP_VERSION: 'v0.1.0',
|
||||
APP_HOME: 'https://github.com/conversejs/converse-desktop',
|
||||
APP_RELEASES_CHECK_URL: 'https://api.github.com/repos/conversejs/converse-desktop/releases',
|
||||
APP_RELEASES_URL: 'https://github.com/conversejs/converse-desktop/releases'
|
||||
});
|
||||
|
||||
module.exports = angApp
|
|
@ -1,22 +0,0 @@
|
|||
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.APP_STATE_ABOUT = 'about'
|
||||
|
||||
stateService.set = (state) => {
|
||||
stateService.previousState = typeof stateService.state !== 'undefined' ?
|
||||
stateService.state : stateService.APP_STATE_DEFAULT
|
||||
stateService.state = state
|
||||
$rootScope.$broadcast('app:state:changed', stateService.state)
|
||||
}
|
||||
|
||||
stateService.set(stateService.APP_STATE_DEFAULT)
|
||||
|
||||
return stateService
|
||||
}])
|
|
@ -1,54 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.factory('CredentialsServise', () => {
|
||||
|
||||
const keytar = require('keytar')
|
||||
const settings = require('electron-settings')
|
||||
|
||||
let credentialsService = {}
|
||||
|
||||
credentialsService.getCredentials = () => {
|
||||
let credentials = {}
|
||||
credentials.login = settings.get('login')
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
if (credentials.login) {
|
||||
credentials.connectionManager = settings.get('connectionManager')
|
||||
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
|
||||
}
|
||||
|
||||
credentialsService.addCredentials = (connectionManager, login, password) => {
|
||||
let xmppService = login.split('@').pop()
|
||||
settings.set('connectionManager', connectionManager)
|
||||
settings.set('login', login)
|
||||
keytar.setPassword(xmppService, login, password)
|
||||
}
|
||||
|
||||
credentialsService.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('connectionManager')
|
||||
resolve()
|
||||
}, (error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
return promise
|
||||
}
|
||||
|
||||
return credentialsService
|
||||
})
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
let angApp = require(__dirname + '/../init')
|
||||
|
||||
const desktopPlugin = require(__dirname +'/../../libs/converse.js/converse-desktop/desktop-plugin')
|
||||
|
||||
angApp.factory('DesktopService', (
|
||||
$window, $timeout, CredentialsServise, SystemService, AppStateService,
|
||||
SettingsService, XmppHelperService
|
||||
) => {
|
||||
|
||||
let desktopService = {}
|
||||
|
||||
desktopService._notifyMessage = () => {
|
||||
SystemService.playAudio()
|
||||
SystemService.showEnvelope()
|
||||
}
|
||||
|
||||
desktopService._hideNotifyMessage = () => {
|
||||
SystemService.hideEnvelope()
|
||||
}
|
||||
|
||||
desktopService.logout = () => {
|
||||
let credentials = CredentialsServise.getCredentials()
|
||||
credentials.then((result) => {
|
||||
let remove = CredentialsServise.removeCredentials(result.login)
|
||||
console.log('Remove credentials on logout')
|
||||
remove.then(() => {
|
||||
AppStateService.set(AppStateService.APP_STATE_LOGIN)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
desktopService.initConverse = (connectionManager, login, password) => {
|
||||
AppStateService.set(AppStateService.APP_STATE_DEFAULT) // Always set to default state before init
|
||||
desktopPlugin.register(login)
|
||||
let lang = navigator.language
|
||||
let allowBookmarks = SettingsService.get('allowBookmarks')
|
||||
let omemoDefault = SettingsService.get('omemoDefault')
|
||||
let xmppResource = XmppHelperService.getResourceFromJid(login)
|
||||
if (!xmppResource) {
|
||||
xmppResource = '.' + (Math.random().toString(36)+'00000000000000000').slice(2, 7) // Generate 5 char unique str
|
||||
login = login + '/converseDesktop'+xmppResource
|
||||
}
|
||||
let conversejsParams = {
|
||||
assets_path: './node_modules/converse.js/dist/',
|
||||
allow_bookmarks: allowBookmarks,
|
||||
auto_login: true,
|
||||
auto_reconnect: true,
|
||||
// debug: true,
|
||||
i18n: lang,
|
||||
jid: login,
|
||||
omemo_default: omemoDefault,
|
||||
password: password,
|
||||
play_sounds: false,
|
||||
priority: 50,
|
||||
view_mode: 'embedded',
|
||||
whitelisted_plugins: ['converseDesktop'],
|
||||
}
|
||||
if (connectionManager.startsWith('ws')) {
|
||||
conversejsParams.websocket_url = connectionManager
|
||||
} else {
|
||||
conversejsParams.bosh_service_url = connectionManager
|
||||
}
|
||||
$timeout(() => {
|
||||
converse.initialize(conversejsParams)
|
||||
}, 50)
|
||||
}
|
||||
|
||||
desktopService.getCredentialsAndLogin = () => {
|
||||
let credentials = CredentialsServise.getCredentials()
|
||||
credentials.then((result) => {
|
||||
desktopService.initConverse(result.connectionManager, result.login, result.password)
|
||||
}, (error) => {
|
||||
AppStateService.set(AppStateService.APP_STATE_LOGIN)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
desktopService.chatToOpen = null
|
||||
|
||||
$window.document.addEventListener('conversejs-logout', function (e) {
|
||||
desktopService.logout()
|
||||
})
|
||||
|
||||
$window.document.addEventListener('conversejs-unread', function (e) {
|
||||
let sender = e.detail
|
||||
desktopService.chatToOpen = sender
|
||||
desktopService._notifyMessage()
|
||||
})
|
||||
|
||||
$window.document.addEventListener('conversejs-no-unread', function (e) {
|
||||
desktopService._hideNotifyMessage()
|
||||
})
|
||||
|
||||
return desktopService
|
||||
|
||||
})
|
|
@ -1,109 +0,0 @@
|
|||
let angApp = require(__dirname+'/../init')
|
||||
|
||||
angApp.factory('SettingsService', () => {
|
||||
|
||||
let settingsService = {}
|
||||
|
||||
const electronSettings = require('electron-settings')
|
||||
|
||||
const settings = {
|
||||
converseDesktop: {
|
||||
runMinimized: {
|
||||
default: false,
|
||||
title: 'Run minimized',
|
||||
hint: 'Default: false. Whether run Converse Desktop minimized to tray or not.'
|
||||
},
|
||||
minimizeOnClose: {
|
||||
default: false,
|
||||
title: 'Minimize on close',
|
||||
hint: 'Default: false. Minimize or close Converse Desktop window.'
|
||||
},
|
||||
preserveWindowSize: {
|
||||
default: true,
|
||||
title: 'Preserve window size',
|
||||
hint: 'Default: true, 800x600 otherwise.'
|
||||
},
|
||||
preserveWindowPosition: {
|
||||
default: true,
|
||||
title: 'Preserve window position',
|
||||
hint: 'Default: true, screen center otherwise.'
|
||||
}
|
||||
},
|
||||
conversejs: {
|
||||
allowBookmarks: {
|
||||
default: false,
|
||||
title: 'Allow server bookmarks',
|
||||
hint: 'Default: false. Enables/disables chatroom bookmarks functionality.'
|
||||
},
|
||||
omemoDefault: {
|
||||
default: false,
|
||||
title: 'Use OMEMO encryption by default',
|
||||
hint: 'Default: false. Use OMEMO encryption by default when the chat supports it.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const iterateSettings = (callback, settingsObj) => {
|
||||
if(typeof settingsObj === "undefined") {
|
||||
settingsObj = settings
|
||||
}
|
||||
angular.forEach(settingsObj, (value, key) => {
|
||||
let settingsList = settingsObj[key]
|
||||
angular.forEach(settingsList, (value, key) => {
|
||||
let itemDefault = settingsList[key]['default']
|
||||
callback(key, itemDefault, settingsList)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Callback
|
||||
// TODO: replace with promise?
|
||||
const saveDefault = (key, value) => {
|
||||
if (!electronSettings.has(key)) {
|
||||
electronSettings.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Callback
|
||||
const save = (key, defaultValue, settingsList) => {
|
||||
let value = settingsList[key]['value']
|
||||
electronSettings.set(key, value)
|
||||
}
|
||||
|
||||
// Callback
|
||||
const loadAll = (key, defaultValue, settingsList) => {
|
||||
if (!electronSettings.has(key)) {
|
||||
settingsList[key]['value'] = defaultValue
|
||||
}
|
||||
settingsList[key]['value'] = electronSettings.get(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* SettingsService
|
||||
*/
|
||||
settingsService.initDefaults = () => {
|
||||
iterateSettings(saveDefault)
|
||||
// Logout for versions with BOSH only
|
||||
if (electronSettings.has('bosh')) {
|
||||
electronSettings.delete('bosh')
|
||||
electronSettings.delete('login')
|
||||
}
|
||||
}
|
||||
|
||||
settingsService.get = (key) => {
|
||||
return electronSettings.get(key)
|
||||
}
|
||||
|
||||
settingsService.loadAll = () => {
|
||||
let currentSettings = angular.copy(settings)
|
||||
iterateSettings(loadAll, currentSettings)
|
||||
return currentSettings
|
||||
}
|
||||
|
||||
settingsService.saveAll = (currentSettings) => {
|
||||
iterateSettings(save, currentSettings)
|
||||
}
|
||||
|
||||
return settingsService
|
||||
})
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
let angApp = require(__dirname + '/../init')
|
||||
|
||||
angApp.factory('SystemService', () => {
|
||||
|
||||
const remote = require('electron').remote
|
||||
|
||||
let systemService = {}
|
||||
|
||||
systemService.playAudio = () => {
|
||||
var audio = new Audio(__dirname + '/../../resources/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
|
||||
|
||||
})
|
|
@ -1,25 +0,0 @@
|
|||
let angApp = require(__dirname + '/../init')
|
||||
|
||||
angApp.factory('XmppHelperService', [() => {
|
||||
|
||||
let xmppHelperService = {}
|
||||
|
||||
/**
|
||||
* Use function copy from Strophe js lib because converse.js Strophe library
|
||||
* is under private _api and unavailable before converse.js is initialized.
|
||||
* This function is used _before_ converse.js is initialized.
|
||||
*
|
||||
* Get the resource portion of a JID String.
|
||||
* @param {string} jid A JID.
|
||||
* @return {string | null} A String containing the resource.
|
||||
*/
|
||||
xmppHelperService.getResourceFromJid = (jid) => {
|
||||
if (!jid) { return null }
|
||||
const s = jid.split("/")
|
||||
if (s.length < 2) { return null }
|
||||
s.splice(0, 1)
|
||||
return s.join('/')
|
||||
}
|
||||
|
||||
return xmppHelperService
|
||||
}])
|
|
@ -1,35 +0,0 @@
|
|||
<div class="page-about" ng-controller="AboutController">
|
||||
<div class="about-card">
|
||||
<div class="about-card__content">
|
||||
<div class="about-card__logo">
|
||||
<img src="./resources/images/logo.png" srcset="./resources/images/logo@2x.png 2x" alt=""
|
||||
class="chimeverse-branding__img" />
|
||||
</div>
|
||||
<div class="about-card__description">
|
||||
<h3 class="about__title">About {{appInfo.APP_NAME}} {{appInfo.APP_VERSION}}</h3>
|
||||
<div class="about__description">Jabber/XMPP client based on Converse.js and Electron</div>
|
||||
<div> </div>
|
||||
<div class="about__converse-version">
|
||||
Version of <a href="https://conversejs.org/" target="_blank">converse.js</a> is 6.0.1
|
||||
</div>
|
||||
<div class="about__electron-version">
|
||||
Version of <a href="https://www.electronjs.org/" target="_blank">electron</a> is 4.2.12
|
||||
</div>
|
||||
<div> </div>
|
||||
<div class="about__thanks">
|
||||
Thanks to
|
||||
<a href="https://github.com/nick-denry/Chimeverse/graphs/contributors" target="_blank">all contributors</a>
|
||||
</div>
|
||||
<div> </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="about__action">
|
||||
<button class="about__close-button" ng-click="closeAbout()">OK</button>
|
||||
</div>
|
||||
<div> </div>
|
||||
<div class="about__copyright">Copyright © 2019-2020 Nick Denry</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-include src="'./app/views/shared/_footer.html'"></ng-include>
|
|
@ -1,24 +0,0 @@
|
|||
<div class="page-default" ng-controller="DefaultController">
|
||||
<div class="chimeverse-branding noselect">
|
||||
<img src="./resources/images/logo.png" srcset="./resources/images/logo@2x.png 2x" alt=""
|
||||
class="chimeverse-branding__img" />
|
||||
<h3 class="chimeverse-branding__header">{{appInfo.APP_NAME}}</h3>
|
||||
<div class="chimeverse-branding__version">
|
||||
<span>{{appInfo.APP_VERSION}} </span>
|
||||
<span class="chimeverse-branding__update">
|
||||
<span class="update__checking" ng-show="checkingForUpdate == 'inProgress'">checking for update...</span>
|
||||
<span class="update__error" ng-show="checkingForUpdate == 'checkErr'">
|
||||
>_< check for update failed <a href="#" ng-click="checkRetry($event)">retry</a>
|
||||
</span>
|
||||
<span class="update__latest" ng-show="checkingForUpdate == 'latest'">latest version</span>
|
||||
<a class="update__available" href="{{appInfo.APP_RELEASES_URL}}" target="_blank"
|
||||
ng-show="checkingForUpdate == 'updateAvailable'">
|
||||
Update available
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="conversejs-adoption">
|
||||
<div id="conversejs"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,43 +0,0 @@
|
|||
<div class="login-form">
|
||||
<h3 class="login-form__title">Welcome to Converse Desktop</h3>
|
||||
<div class="login-form__description">Jabber/XMPP client based on Converse.js and Electron</div>
|
||||
<div class="login-form__card">
|
||||
<form name="accountForm" ng-controller="LoginController">
|
||||
<div class="login-form__wrapper">
|
||||
<div class="login-form__input-group">
|
||||
<span class="group-prepend oi" data-glyph="link-intact"></span>
|
||||
<input ng-model="credentials.connectionManager" class="login-form__input login-form__input--with-append" type="text" placeholder="Connection manager url" required>
|
||||
<span class="group-append--backgrounded oi" data-glyph="info" ng-click="showHelp('connectionManager')"></span>
|
||||
</div>
|
||||
<div class="login-form__input-help" ng-show="help.connectionManager == true"">
|
||||
<div>
|
||||
Should be a
|
||||
<a href="https://m.conversejs.org/docs/html/setup.html#bosh-section" target="_blank">BOSH service</a>
|
||||
or a
|
||||
<a href="https://m.conversejs.org/docs/html/setup.html#websocket-section" target="_blank">Websocket</a>
|
||||
URL
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form__wrapper">
|
||||
<div class="login-form__input-group">
|
||||
<span class="group-prepend oi" data-glyph="person"></span>
|
||||
<input ng-model="credentials.login" class="login-form__input" type="text" placeholder="jid@jabber.org" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form__wrapper">
|
||||
<div class="login-form__input-group">
|
||||
<span class="group-prepend oi" data-glyph="lock-locked"></span>
|
||||
<input ng-model="credentials.password" class="login-form__input" type="password" placeholder="Password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form__wrapper">
|
||||
<button class="login-form__button" ng-click="addAccountAndLoginAction()" ng-disabled="accountForm.$invalid" disabled>Add account</button>
|
||||
</div>
|
||||
<div class="login-form__credentials-message">
|
||||
Credentials stored via <a href="https://atom.github.io/node-keytar/" target="_blank">Keychain</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<ng-include src="'./app/views/shared/_footer.html'"></ng-include>
|
|
@ -1,28 +0,0 @@
|
|||
<div class="settings-page" ng-controller="SettingsController">
|
||||
<form name="settignsForm">
|
||||
<h3 class="settings-page__title">Chimeverse settings</h3>
|
||||
<div class="form-item" ng-repeat="(key, item) in settings.converseDesktop">
|
||||
<label>
|
||||
<input type="checkbox" name="{{key}}" ng-model="item.value" /> {{item.title}}
|
||||
</label>
|
||||
<div class="form-item__hint">{{item.hint}}</div>
|
||||
</div>
|
||||
<h3 class="settings-page__title">Converse.js settings</h3>
|
||||
<div class="form-item" ng-repeat="(key, item) in settings.conversejs">
|
||||
<label>
|
||||
<input type="checkbox" name="{{key}}" ng-model="item.value" /> {{item.title}}
|
||||
</label>
|
||||
<div class="form-item__hint">{{item.hint}}</div>
|
||||
</div>
|
||||
<div class="form-item" ng-show="settingsSaved">
|
||||
<a href="#" ng-click="restartApp()" class="form-item__restart-app">
|
||||
Click here to restart the app and apply your changes
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="form-item__save-button" ng-class="{'active': settingsChanged == true}" ng-click="saveSettings()">Save</button>
|
||||
<button class="form-item__cancel-button" ng-click="closeSettings()">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<ng-include src="'./app/views/shared/_footer.html'"></ng-include>
|
|
@ -1,4 +0,0 @@
|
|||
<div class="page__footer" ng-controller="FooterController">
|
||||
<span class="footer__version">{{appInfo.APP_NAME}} {{appInfo.APP_VERSION}}.</span>
|
||||
<a class="github-button" href="{{appInfo.APP_HOME}}" data-icon="octicon-star" aria-label="Star nick-denry/Chimeverse on GitHub">Star</a>
|
||||
</div>
|
60
index.html
|
@ -3,61 +3,19 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Converse Desktop</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="node_modules/open-iconic/font/css/open-iconic.css">
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="node_modules/converse.js/dist/converse.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/app.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/_footer.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/page-about.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/page-default.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/page-login.css">
|
||||
<link rel="stylesheet" type="text/css" href="resources/css/page-settings.css">
|
||||
</head>
|
||||
<base href="./">
|
||||
<body ng-app="app">
|
||||
<div class="main-background"></div>
|
||||
<div class="main-window" ng-controller="AppController" ng-cloak>
|
||||
<div ng-show="state == 'default'">
|
||||
<ng-include src="'./app/views/default/page.html'"></ng-include>
|
||||
</div>
|
||||
<div ng-show="state == 'login'">
|
||||
<ng-include src="'./app/views/login/page.html'"></ng-include>
|
||||
</div>
|
||||
<div ng-show="state == 'about'">
|
||||
<ng-include src="'./app/views/about/page.html'"></ng-include>
|
||||
</div>
|
||||
<div ng-show="state == 'settings'">
|
||||
<ng-include src="'./app/views/settings/page.html'"></ng-include>
|
||||
<base href="./index.html">
|
||||
<body class="converse-fullscreen">
|
||||
<div class="main-window">
|
||||
<div class="page-default">
|
||||
<div id="conversejs-bg"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
@see comment https://github.com/signalapp/libsignal-protocol-javascript/issues/6#issuecomment-247208665
|
||||
-->
|
||||
<script>
|
||||
window.nodeRequire = require
|
||||
delete window.require
|
||||
</script>
|
||||
<!-- Place libsignal at libs dir as it's no more distributed with converse.js -->
|
||||
<script src="libs/converse.js/3rdparty/libsignal-protocol.js"></script>
|
||||
<script>
|
||||
window.require = window.nodeRequire
|
||||
delete window.nodeRequire
|
||||
</script>
|
||||
<script>
|
||||
// You can also require other files to run in this process
|
||||
require('./node_modules/converse.js/dist/emojis.js')
|
||||
require('./node_modules/converse.js/dist/converse.js')
|
||||
require('./renderer.js')
|
||||
</script>
|
||||
<script>
|
||||
function loadJs(url) {
|
||||
var script = document.createElement('script')
|
||||
script.src = url
|
||||
script.setAttribute('async', 'true')
|
||||
document.documentElement.firstChild.appendChild(script)
|
||||
}
|
||||
setTimeout(function () {
|
||||
loadJs("./node_modules/github-buttons/dist/buttons.min.js")
|
||||
}, 500)
|
||||
</script>
|
||||
<script src="./3rdparty/libsignal-protocol.js"></script>
|
||||
<script src="./node_modules/converse.js/dist/converse.min.js"></script>
|
||||
<script type="module" src="./setup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
let desktopPlugin = {}
|
||||
|
||||
desktopPlugin.register = (login) => {
|
||||
converse.plugins.add('converseDesktop', {
|
||||
initialize: (event) => {
|
||||
let _converse = event.properties._converse
|
||||
let Strophe = converse.env.Strophe
|
||||
|
||||
/**
|
||||
* Check if message stanza has some body payload
|
||||
* @param {*} stanzaNodes
|
||||
*/
|
||||
let isBodyMessage = (stanzaNodes) => {
|
||||
let result = false
|
||||
Object.keys(stanzaNodes).some((key) => {
|
||||
if (stanzaNodes[key].nodeName == 'body') {
|
||||
result = true
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
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) => {
|
||||
// Display notifications only for "payloaded" messages
|
||||
if (isBodyMessage(data.stanza.childNodes)) {
|
||||
let sender = data.stanza.attributes.from.nodeValue
|
||||
let senderJid = Strophe.getBareJidFromJid(sender)
|
||||
let loginJid = Strophe.getBareJidFromJid(login)
|
||||
if (senderJid != loginJid) {
|
||||
console.log(senderJid)
|
||||
let event = new CustomEvent('conversejs-unread', {detail: senderJid})
|
||||
document.dispatchEvent(event)
|
||||
}
|
||||
}
|
||||
})
|
||||
_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()
|
||||
})
|
||||
window.document.addEventListener('conversejs-open-chat', function (e) {
|
||||
let chatToOpen = e.detail
|
||||
console.log('Get open-unread-chat event: '+chatToOpen)
|
||||
if (chatToOpen !== null) {
|
||||
_converse.api.chats.open(chatToOpen)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = desktopPlugin
|
146
main.js
|
@ -1,19 +1,24 @@
|
|||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, shell } = require('electron')
|
||||
const path = require('path');
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
// Require other app modules
|
||||
const trayService = require(__dirname+'/modules/tray-service')
|
||||
const menuService = require(__dirname+'/modules/menu-service')
|
||||
const settingsService = require(__dirname+'/modules/settings-service')
|
||||
const trayService = require(__dirname + '/modules/tray-service')
|
||||
const menuService = require(__dirname + '/modules/menu-service')
|
||||
const settingsService = require(__dirname + '/modules/settings-service')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
const isWin = process.platform === 'win32'
|
||||
|
||||
function initApp() {
|
||||
function initApp () {
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit();
|
||||
}
|
||||
|
||||
createWindow()
|
||||
// Set Windows platform notifications
|
||||
if (isWin) {
|
||||
|
@ -23,88 +28,39 @@ function initApp() {
|
|||
|
||||
function createWindow () {
|
||||
// Main window options
|
||||
let mainWindowOptions = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
minWidth: 780,
|
||||
minHeight: 560,
|
||||
const mainWindowOptions = {
|
||||
zoomToPageWidth: true,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
}
|
||||
|
||||
// Load app settings
|
||||
let runMinimized = settingsService.get('runMinimized')
|
||||
if (runMinimized) {
|
||||
mainWindowOptions.show = !runMinimized
|
||||
}
|
||||
let preserveWindowSize = settingsService.get('preserveWindowSize')
|
||||
if (preserveWindowSize) {
|
||||
let width = settingsService.get('windowWidth')
|
||||
let height = settingsService.get('windowHeight')
|
||||
if (width) mainWindowOptions.width = width
|
||||
if (height) mainWindowOptions.height = height
|
||||
}
|
||||
|
||||
let preserveWindowPosition = settingsService.get('preserveWindowPosition')
|
||||
if (preserveWindowPosition) {
|
||||
let windowX = settingsService.get('windowX')
|
||||
let windowY = settingsService.get('windowY')
|
||||
if (windowX) mainWindowOptions.x = windowX
|
||||
if (windowY) mainWindowOptions.y = windowY
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
},
|
||||
icon: './resources/images/logo.png',
|
||||
}
|
||||
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow(mainWindowOptions)
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Init tray
|
||||
trayService.initTray(mainWindow)
|
||||
|
||||
// Init menu
|
||||
menuService.createMenu()
|
||||
menuService.createMenu(mainWindow)
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Before close
|
||||
let minimizeOnClose = settingsService.get('minimizeOnClose')
|
||||
if (minimizeOnClose) {
|
||||
mainWindow.on('close', (e) => {
|
||||
if (!app.isQuitting) {
|
||||
e.preventDefault()
|
||||
mainWindow.hide()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Save window size
|
||||
if (preserveWindowSize) {
|
||||
mainWindow.on('resize', (e) => {
|
||||
let newSize = mainWindow.getSize()
|
||||
let width = newSize[0]
|
||||
let height = newSize[1]
|
||||
settingsService.set('windowWidth', width)
|
||||
settingsService.set('windowHeight', height)
|
||||
})
|
||||
}
|
||||
|
||||
// Save window position
|
||||
if (preserveWindowPosition !== 'undefined') {
|
||||
mainWindow.on('move', (e) => {
|
||||
let newPosition = mainWindow.getPosition()
|
||||
let windowX = newPosition[0]
|
||||
let windowY = newPosition[1]
|
||||
settingsService.set('windowX', windowX)
|
||||
settingsService.set('windowY', windowY)
|
||||
})
|
||||
}
|
||||
mainWindow.on('close', (e) => {
|
||||
if (!app.isQuitting && settingsService.get('minimizeOnClose')) {
|
||||
e.preventDefault()
|
||||
mainWindow.hide()
|
||||
}
|
||||
return false;
|
||||
})
|
||||
|
||||
// Handle shutdown event on Mac with minimizeOnClose
|
||||
// to prevent shutdown interrupt
|
||||
if (isMac && minimizeOnClose) {
|
||||
if (isMac) {
|
||||
const { powerMonitor } = require('electron')
|
||||
powerMonitor.on('shutdown', () => {
|
||||
app.isQuitting = true
|
||||
|
@ -113,10 +69,9 @@ function createWindow () {
|
|||
}
|
||||
|
||||
// Handle restart
|
||||
ipcMain.on('app-restart', (evt, arg) => {
|
||||
ipcMain.on('app-quit', () => {
|
||||
app.isQuitting = true
|
||||
app.relaunch()
|
||||
app.exit()
|
||||
app.quit();
|
||||
})
|
||||
|
||||
// Emitted when the window is closed.
|
||||
|
@ -128,10 +83,31 @@ function createWindow () {
|
|||
})
|
||||
|
||||
// Open links on system default browser
|
||||
mainWindow.webContents.on('new-window', function(e, url) {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
mainWindow.webContents.setWindowOpenHandler(function (details) {
|
||||
shell.openExternal(details.url).catch((reason) => {
|
||||
console.log(reason);
|
||||
});
|
||||
return { action: 'deny' };
|
||||
})
|
||||
|
||||
ipcMain.handle('settings', (e, method, ...args) => {
|
||||
return settingsService[method].apply(settingsService, args);
|
||||
});
|
||||
|
||||
ipcMain.handle('trayService', (e, method, ...args) => {
|
||||
return trayService[method].apply(trayService, args);
|
||||
});
|
||||
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
mainWindow.maximize();
|
||||
});
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html').catch((reason) => {
|
||||
console.log(reason);
|
||||
app.isQuitting = true;
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
|
@ -141,7 +117,7 @@ app.on('ready', initApp)
|
|||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// On macOS, it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
// if (process.platform !== 'darwin')
|
||||
// ^^^^ NOPE ;)
|
||||
|
@ -150,19 +126,19 @@ app.on('window-all-closed', function () {
|
|||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) createWindow()
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
} else {
|
||||
mainWindow.show();
|
||||
}
|
||||
})
|
||||
|
||||
app.on('second-instance', function () {
|
||||
mainWindow.show();
|
||||
});
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
// Allow to play audio automatically
|
||||
// Allow audio to play automatically
|
||||
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required')
|
||||
|
||||
/**
|
||||
* Export functions
|
||||
*/
|
||||
|
||||
exports.trayService = trayService
|
||||
|
|
|
@ -1,59 +1,37 @@
|
|||
/**
|
||||
* Module for Menu functions.
|
||||
*/
|
||||
const { app, Menu, MenuItem } = require('electron')
|
||||
const settingsService = require(__dirname + '/../modules/settings-service')
|
||||
|
||||
const {app, Menu, BrowserWindow} = require('electron')
|
||||
|
||||
let menuService = {}
|
||||
const menuService = {}
|
||||
|
||||
|
||||
menuService.createMenu = () => {
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
const about = {
|
||||
label: 'About Converse Desktop',
|
||||
click: () => {
|
||||
// @see https://github.com/electron/electron/issues/16558#issuecomment-484460276
|
||||
// let activeWindow = BrowserWindow.getFocusedWindow()
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.show()
|
||||
activeWindow.webContents.send('about-page-event')
|
||||
}
|
||||
}
|
||||
|
||||
const application = {
|
||||
label: 'Converse Desktop',
|
||||
submenu: [
|
||||
... isMac ? [about] : [],
|
||||
menuService.createMenu = (window) => {
|
||||
let converse;
|
||||
const application = new Menu();
|
||||
application.append(new MenuItem({
|
||||
label: 'Converse Desktop'
|
||||
, submenu: converse = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Reconnect',
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: () => {
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.show()
|
||||
activeWindow.reload()
|
||||
window.show()
|
||||
window.loadFile('index.html').catch((reason) => {
|
||||
console.log(reason);
|
||||
app.isQuitting = true;
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Force logout',
|
||||
accelerator: 'CmdOrCtrl+D',
|
||||
label: 'Minimize on close',
|
||||
type: 'checkbox',
|
||||
id: 'minimize-on-close',
|
||||
checked: settingsService.get('minimizeOnClose'),
|
||||
click: () => {
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.show()
|
||||
activeWindow.webContents.send('force-logout-event')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator',
|
||||
},
|
||||
{
|
||||
label: 'Preferences',
|
||||
accelerator: 'CmdOrCtrl+,',
|
||||
click: () => {
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.show()
|
||||
activeWindow.webContents.send('preferences-event')
|
||||
settingsService.set('minimizeOnClose', converse.getMenuItemById('minimize-on-close').checked);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -67,12 +45,11 @@ menuService.createMenu = () => {
|
|||
app.quit()
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const edit = {
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
])
|
||||
}));
|
||||
application.append(new MenuItem({
|
||||
label: 'Edit'
|
||||
, submenu: Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'CmdOrCtrl+Z',
|
||||
|
@ -104,27 +81,22 @@ menuService.createMenu = () => {
|
|||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectAll',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const help = {
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
... !isMac ? [about] : [],
|
||||
])
|
||||
}));
|
||||
application.append(new MenuItem({
|
||||
label: 'Help'
|
||||
, submenu: Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Debug info',
|
||||
accelerator: 'F12',
|
||||
click: () => {
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.webContents.openDevTools()
|
||||
window.webContents.openDevTools()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
}));
|
||||
|
||||
const template = [application, edit, help]
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
|
||||
Menu.setApplicationMenu(application);
|
||||
}
|
||||
|
||||
module.exports = menuService
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Module for getting settigns in Main process.
|
||||
* Module for getting settings in Main process.
|
||||
*/
|
||||
|
||||
const electronSettings = require('electron-settings')
|
||||
|
@ -7,7 +7,7 @@ const electronSettings = require('electron-settings')
|
|||
let settingsService = {}
|
||||
|
||||
settingsService.get = (itemKey) => {
|
||||
settingValue = electronSettings.get(itemKey)
|
||||
const settingValue = electronSettings.getSync(itemKey)
|
||||
if (typeof settingValue === 'undefined' || settingValue === null) {
|
||||
return false
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ settingsService.get = (itemKey) => {
|
|||
}
|
||||
|
||||
settingsService.set = (itemKey, settingValue) => {
|
||||
electronSettings.set(itemKey, settingValue)
|
||||
electronSettings.setSync(itemKey, settingValue)
|
||||
}
|
||||
|
||||
module.exports = settingsService
|
||||
settingsService.has = (itemKey) => electronSettings.hasSync(itemKey);
|
||||
|
||||
settingsService.unset = (itemKey) => electronSettings.unsetSync(itemKey);
|
||||
|
||||
module.exports = settingsService
|
||||
|
|
|
@ -2,50 +2,42 @@
|
|||
* Module for Tray functions.
|
||||
*/
|
||||
|
||||
const { BrowserWindow, Tray } = require('electron')
|
||||
const { Tray } = require('electron')
|
||||
|
||||
const path = require('path')
|
||||
|
||||
let trayServiceWindow = null
|
||||
let tray = null
|
||||
|
||||
let trayService = {}
|
||||
const trayService = {}
|
||||
|
||||
let getTrayServiceIcon = (iconName = 'icon') => {
|
||||
let iconImage = ''
|
||||
if (process.platform === 'darwin') {
|
||||
iconImage = iconName+'Template'
|
||||
const getTrayServiceIcon = (iconName = 'icon') => {
|
||||
let iconImage;
|
||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||
iconImage = iconName + '-16x16'
|
||||
} else {
|
||||
iconImage = iconName + '-48x48'
|
||||
}
|
||||
else if (process.platform === 'win32') {
|
||||
iconImage = iconName+'-16x16'
|
||||
}
|
||||
else {
|
||||
iconImage = iconName+'-48x48'
|
||||
}
|
||||
return path.join(__dirname, '/../resources/images/' + iconImage + '.png')
|
||||
return path.join(__dirname, '..', 'resources', 'images', iconImage + '.png')
|
||||
}
|
||||
|
||||
trayService.initTray = (window) => {
|
||||
trayServiceWindow = window
|
||||
let iconPath = getTrayServiceIcon()
|
||||
const iconPath = getTrayServiceIcon()
|
||||
tray = new Tray(iconPath)
|
||||
tray.setToolTip('Converse Desktop')
|
||||
tray.on('click', function() {
|
||||
// Sent open-related-chat event only on click
|
||||
let activeWindow = BrowserWindow.getAllWindows()[0]
|
||||
activeWindow.webContents.send('open-unread-chat')
|
||||
tray.on('click', function () {
|
||||
window.webContents.send('open-unread-chat')
|
||||
trayService.hideEnvelope()
|
||||
trayServiceWindow.show()
|
||||
window.show()
|
||||
})
|
||||
}
|
||||
|
||||
trayService.showEnvelope = () => {
|
||||
let iconPath = getTrayServiceIcon('envelope')
|
||||
const iconPath = getTrayServiceIcon('envelope')
|
||||
tray.setImage(iconPath)
|
||||
}
|
||||
|
||||
trayService.hideEnvelope = () => {
|
||||
let iconPath = getTrayServiceIcon()
|
||||
const iconPath = getTrayServiceIcon()
|
||||
tray.setImage(iconPath)
|
||||
}
|
||||
|
||||
|
|
40
package.json
|
@ -1,16 +1,18 @@
|
|||
{
|
||||
"name": "@converse/desktop",
|
||||
"version": "0.1.0",
|
||||
"version": "9.1.0",
|
||||
"description": "Desktop Jabber/XMPP client based on Converse.js and Electron",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"clean": "rm -rf node_modules",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"start": "electron .",
|
||||
"pack": "build --dir",
|
||||
"dist": "build",
|
||||
"dist:win64": "build --platform win --arch x64",
|
||||
"dist:linux64deb": "build --platform linux --arch x64"
|
||||
"pack": "electron-builder --dir",
|
||||
"dist": "electron-builder --mac",
|
||||
"dist:win64": "electron-builder --win --x64",
|
||||
"dist:linux64": "electron-builder --linux --x64"
|
||||
},
|
||||
"author": "The Converse Desktop Developers",
|
||||
"repository": "https://github.com/conversejs/converse-desktop",
|
||||
"keywords": [
|
||||
"Jabber",
|
||||
|
@ -20,22 +22,17 @@
|
|||
"Electron",
|
||||
"OMEMO"
|
||||
],
|
||||
"author": "Nick Denry <nick@denry.ru>",
|
||||
"license": "MPL-2.0",
|
||||
"devDependencies": {
|
||||
"electron": "^4.2.12",
|
||||
"electron-builder": "^20.44.4",
|
||||
"electron-packager": "^13.1.1",
|
||||
"electron-rebuild": "^1.10.1"
|
||||
"electron": "^18.0.0",
|
||||
"electron-builder": "^22.14.0",
|
||||
"electron-packager": "^15.2.0",
|
||||
"eslint": "^8.12.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"angular": "^1.7.9",
|
||||
"converse.js": "^6.0.0",
|
||||
"electron-settings": "^3.2.0",
|
||||
"github-buttons": "^2.8.0",
|
||||
"keytar": "^4.13.0",
|
||||
"n": "^6.5.1",
|
||||
"open-iconic": "^1.1.1"
|
||||
"converse.js": "^9.1.0",
|
||||
"electron-settings": "^4.0.2",
|
||||
"keytar": "^7.9.0"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.denry.converse-desktop",
|
||||
|
@ -60,13 +57,18 @@
|
|||
]
|
||||
},
|
||||
"linux": {
|
||||
"maintainer": "Keith Maika <keithm@aoeex.com>",
|
||||
"artifactName": "converse_desktop-${version}_${arch}.${ext}",
|
||||
"icon": "resources/images/logo.png",
|
||||
"target": [
|
||||
"deb"
|
||||
"deb",
|
||||
"tar.gz",
|
||||
"appImage"
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"target": "nsis",
|
||||
"icon": "resources/images/logo.ico"
|
||||
"icon": "resources/images/logo.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
const { ipcRenderer, contextBridge } = require('electron');
|
||||
const keytar = require('keytar');
|
||||
|
||||
contextBridge.exposeInMainWorld('api', {
|
||||
settings: {
|
||||
has (setting) {
|
||||
return ipcRenderer.invoke('settings', 'has', setting);
|
||||
},
|
||||
set (setting, value) {
|
||||
return ipcRenderer.invoke('settings', 'set', setting, value);
|
||||
},
|
||||
unset (setting) {
|
||||
return ipcRenderer.invoke('settings', 'unset', setting);
|
||||
},
|
||||
get (setting) {
|
||||
return ipcRenderer.invoke('settings', 'get', setting);
|
||||
}
|
||||
},
|
||||
trayService: {
|
||||
showEnvelope () {
|
||||
return ipcRenderer.invoke('trayService', 'showEnvelope');
|
||||
},
|
||||
hideEnvelope () {
|
||||
return ipcRenderer.invoke('trayService', 'hideEnvelope');
|
||||
}
|
||||
},
|
||||
keytar: {
|
||||
getPassword (service, login) {
|
||||
return keytar.getPassword(service, login);
|
||||
},
|
||||
setPassword (service, login, password) {
|
||||
return keytar.setPassword(service, login, password);
|
||||
},
|
||||
deletePassword (service, login) {
|
||||
return keytar.deletePassword(service, login);
|
||||
}
|
||||
},
|
||||
app: {
|
||||
quit () {
|
||||
ipcRenderer.send('app-quit');
|
||||
}
|
||||
}
|
||||
});
|
64
renderer.js
|
@ -1,64 +0,0 @@
|
|||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// All of the Node.js APIs are available in this process.
|
||||
|
||||
var angApp = require('./app/init')
|
||||
|
||||
require('./app/services/credentials-service')
|
||||
require('./app/services/settings-service')
|
||||
require('./app/services/system-service')
|
||||
require('./app/services/app-state-service')
|
||||
require('./app/services/xmpp-helper-service')
|
||||
require('./app/services/desktop-service')
|
||||
require('./app/controllers/settings-controller')
|
||||
require('./app/controllers/login-controller')
|
||||
require('./app/controllers/default-controller')
|
||||
require('./app/controllers/about-controller')
|
||||
require('./app/controllers/footer-controller')
|
||||
|
||||
angApp.controller('AppController', function ($scope, $timeout, DesktopService, SettingsService, AppStateService) {
|
||||
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
// Menu force logout event
|
||||
ipcRenderer.on('force-logout-event', () => {
|
||||
DesktopService.logout()
|
||||
let event = new CustomEvent("converse-force-logout") // Dispatch to the plugin
|
||||
document.dispatchEvent(event)
|
||||
})
|
||||
|
||||
// Menu settings event
|
||||
ipcRenderer.on('preferences-event', () => {
|
||||
AppStateService.set(AppStateService.APP_STATE_SETTINGS)
|
||||
})
|
||||
|
||||
// Menu about event
|
||||
ipcRenderer.on('about-page-event', () => {
|
||||
AppStateService.set(AppStateService.APP_STATE_ABOUT)
|
||||
})
|
||||
|
||||
// Menu about event
|
||||
ipcRenderer.on('open-unread-chat', () => {
|
||||
let event = new CustomEvent('conversejs-open-chat', {detail: DesktopService.chatToOpen})
|
||||
document.dispatchEvent(event)
|
||||
})
|
||||
|
||||
AppStateService.set(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('Switch to the "' + $scope.state +'" state')
|
||||
}, 0)
|
||||
})
|
||||
|
||||
$scope.$on('app:restart', (event, data) => {
|
||||
ipcRenderer.send('app-restart')
|
||||
})
|
||||
|
||||
SettingsService.initDefaults()
|
||||
|
||||
DesktopService.getCredentialsAndLogin()
|
||||
|
||||
})
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
.page__footer {
|
||||
bottom: 20px;
|
||||
color: #777;
|
||||
display: flex;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
transform: translate(-50%, 0%);
|
||||
}
|
||||
|
||||
.footer__version {
|
||||
font-size: 13px;
|
||||
margin-right: 30px;
|
||||
}
|
|
@ -1,7 +1,3 @@
|
|||
[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 */
|
||||
|
@ -20,22 +16,12 @@ a {
|
|||
color: #777;
|
||||
}
|
||||
|
||||
.main-background {
|
||||
background: #f8f8f8;
|
||||
height: 100%;
|
||||
left: 0px;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.conversejs-adoption {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -46,4 +32,13 @@ a {
|
|||
|
||||
#conversejs .converse-chatboxes > * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded .chatbox {
|
||||
flex-grow: 1 !important;
|
||||
flex-shrink: 1 !important;
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
.page-about {
|
||||
color: #777;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 47%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.about-card {
|
||||
background: #fff;
|
||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
|
||||
margin-top: 30px;
|
||||
min-width: 400px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.about-card__content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.about__action {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.about__close-button {
|
||||
border: 0px solid #ddd;
|
||||
background: rgb(5,93,228);
|
||||
background: linear-gradient(0deg, rgba(5,93,228,1) 0%, rgba(76,145,255,1) 100%);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 18px;
|
||||
outline: none;
|
||||
padding: 10px 30px;
|
||||
}
|
||||
|
||||
.about__copyright {
|
||||
text-align: center;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
.chimeverse-branding {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chimeverse-branding__img {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.chimeverse-branding__header {
|
||||
font-size: 26px;
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.chimeverse-branding__version {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.update__latest {
|
||||
background: #bbb;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
|
||||
.update__available {
|
||||
background: rgb(5,93,228);
|
||||
background: linear-gradient(0deg, rgba(5,93,228,1) 0%, rgba(76,145,255,1) 100%);
|
||||
padding: 3px 5px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.update__error {
|
||||
color: #da0000;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
.login-form {
|
||||
color: #777;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 47%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.login-form__title {
|
||||
font-size: 28px;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
margin: 0px 0px 15px 0px;
|
||||
}
|
||||
|
||||
.login-form__description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-form__card {
|
||||
background: #fff;
|
||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
|
||||
margin-top: 30px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.login-form__wrapper {
|
||||
margin-bottom: 15px;;
|
||||
}
|
||||
|
||||
.login-form__input-group {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0px;
|
||||
padding: 0px 0px 0px 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-form__input-group:active,
|
||||
.login-form__input-group:focus,
|
||||
.login-form__input-group:hover {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.login-form__input-group .group-prepend {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.login-form__input-group .group-append--backgrounded {
|
||||
background: #f2f2f2;
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 0 px;
|
||||
}
|
||||
|
||||
.login-form__input {
|
||||
border: 0px;
|
||||
color: #222;
|
||||
font-size: 18px;
|
||||
outline: none;
|
||||
padding: 10px;
|
||||
width: 290px;
|
||||
}
|
||||
|
||||
.login-form__input::placeholder { /* Most modern browsers support this now. */
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.login-form__input--with-append {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
.login-form__input-help {
|
||||
font-size: 13px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.login-form__button {
|
||||
border: 1px solid #ddd;
|
||||
background: rgb(5,93,228);
|
||||
background: linear-gradient(0deg, rgba(5,93,228,1) 0%, rgba(76,145,255,1) 100%);
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
font-size: 18px;
|
||||
outline: none;
|
||||
padding: 10px 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-form__button:disabled {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.login-form__credentials-message {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
.settings-page {
|
||||
padding: 0px 20px 0px 20px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-item__hint {
|
||||
color: #777;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-item__save-button.active {
|
||||
color: blue;
|
||||
}
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 438 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 719 B |
Before Width: | Height: | Size: 701 B After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 399 B |
Before Width: | Height: | Size: 895 B |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,45 @@
|
|||
/* global api */
|
||||
|
||||
await import('./app/converse-plugins/desktop-credentials.js')
|
||||
await import('./app/converse-plugins/desktop-trayicon.js')
|
||||
const getCredentials = (await import('./app/credentials.js')).getCredentials;
|
||||
|
||||
|
||||
let websocket_url, bosh_service_url;
|
||||
const { connectionManager, login, password } = await getCredentials()
|
||||
|
||||
if (connectionManager?.startsWith('ws')) {
|
||||
websocket_url = connectionManager
|
||||
} else if (connectionManager?.startsWith('http')) {
|
||||
bosh_service_url = connectionManager
|
||||
}
|
||||
|
||||
converse.plugins.add('converse-debug', {
|
||||
initialize () {
|
||||
const { _converse } = this;
|
||||
window._converse = _converse;
|
||||
}
|
||||
});
|
||||
|
||||
converse.initialize({
|
||||
assets_path: './node_modules/converse.js/dist/',
|
||||
auto_login: login && password,
|
||||
bosh_service_url,
|
||||
i18n: navigator.language,
|
||||
jid: login,
|
||||
loglevel: 'debug',
|
||||
muc_respect_autojoin: true,
|
||||
muc_show_logs_before_join: true,
|
||||
password: password,
|
||||
play_sounds: false,
|
||||
priority: 50,
|
||||
prune_messages_above: 250,
|
||||
theme: 'concord',
|
||||
view_mode: 'fullscreen',
|
||||
websocket_url,
|
||||
whitelisted_plugins: ['converse-debug', 'converse-desktop-credentials', 'converse-desktop-trayicon'],
|
||||
show_connection_url_input: true
|
||||
}).catch((reason) => {
|
||||
console.log(reason);
|
||||
api.app.quit();
|
||||
});
|