diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..14dc37a --- /dev/null +++ b/Makefile @@ -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 diff --git a/package.json b/package.json new file mode 100644 index 0000000..f8f5a09 --- /dev/null +++ b/package.json @@ -0,0 +1,75 @@ +{ + "name": "@rs/desktop", + "productName": "RS Desktop", + "version": "10.1.5", + "description": "RS Desktop is a Jabber/XMPP client based on Converse-desktop", + "main": "main.js", + "scripts": { + "clean": "rm -rf node_modules", + "postinstall": "electron-builder install-app-deps", + "start": "electron ./main.js", + "pack": "electron-builder --dir", + "dist": "electron-builder --mac --universal", + "dist:win64": "electron-builder --win --x64", + "dist:linux64": "electron-builder --linux --x64" + }, + "author": "RandomServer Community", + "repository": "https://git.randomserver.top/legacytard-association/converse.rs", + "keywords": [ + "RS", + "RandomServer", + "RS Desktop", + "Jabber", + "XMPP", + "Client", + "converse.js", + "Electron", + "OMEMO" + ], + "license": "MPL-2.0", + "type": "module", + "devDependencies": { + "electron": "^28.0.0", + "electron-builder": "^23.0.0", + "electron-packager": "^17.0.0", + "electron-rebuild": "^3.2.9", + "eslint": "^8.12.0" + }, + "dependencies": { + "converse.js": "^10.1.8", + "electron-settings": "^4.0.2", + "keytar": "^7.9.0", + "node-abi": "^4.8.0", + "find-bar": "^0.1.3" + + }, + "build": { + "appId": "com.rscommunity.rs-desktop", + "productName": "RS Desktop", + "extraFiles": [ + { + "from": "resources/images/logo.svg", + "to": "converse-desktop.svg" + } + ], + "mac": { + "category": "public.app-category.social-networking", + "icon": "resources/images/logo.icns", + "target": "dmg" + }, + "linux": { + "maintainer": "RS Community ", + "artifactName": "converse_desktop-${version}_${arch}.${ext}", + "icon": "resources/images", + "target": [ + "deb", + "tar.gz", + "appImage" + ] + }, + "win": { + "target": "nsis", + "icon": "resources/images/logo.ico" + } + } +} diff --git a/preload.cjs b/preload.cjs new file mode 100644 index 0000000..72cba74 --- /dev/null +++ b/preload.cjs @@ -0,0 +1,79 @@ +const { contextBridge, ipcRenderer } = require('electron'); + +const changedHandlers = []; + +ipcRenderer.on('settings', (e, method, setting, newValue) => { + if (method === 'changed') { + for (const handler of changedHandlers) { + try { + handler(setting, newValue); + } catch (err) { + console.error('Error in settings changed handler:', err); + } + } + } +}); + +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); + }, + changed(callback) { + if (typeof callback === 'function') { + changedHandlers.push(callback); + } else { + console.warn('api.settings.changed: callback is not a function'); + } + } + }, + trayService: { + showEnvelope() { + return ipcRenderer.invoke('trayService', 'showEnvelope'); + }, + hideEnvelope() { + return ipcRenderer.invoke('trayService', 'hideEnvelope'); + } + }, + keytar: { + getPassword(service, login) { + return ipcRenderer.invoke('keytar', 'getPassword', service, login); + }, + setPassword(service, login, password) { + return ipcRenderer.invoke('keytar', 'setPassword', service, login, password); + }, + deletePassword(service, login) { + return ipcRenderer.invoke('keytar', 'deletePassword', service, login); + } + }, + app: { + quit() { + ipcRenderer.send('app-quit'); + } + } +}); + +window.addEventListener('wheel', (event) => { + if (event.ctrlKey) { + ipcRenderer.send(event.deltaY > 0 ? 'increaseZoom' : 'decreaseZoom'); + } +}); + +window.addEventListener('keydown', (event) => { + if (event.ctrlKey) { + if (event.key === '+' || event.key === '=') { + ipcRenderer.send('increaseZoom'); + } else if (event.key === '-') { + ipcRenderer.send('decreaseZoom'); + } + } +}); diff --git a/setup.js b/setup.js new file mode 100644 index 0000000..ced9086 --- /dev/null +++ b/setup.js @@ -0,0 +1,55 @@ +(async () => { + await import('./app/converse-plugins/desktop-credentials.js'); + await import('./app/converse-plugins/desktop-trayicon.js'); + await import('./app/converse-plugins/desktop-settings.js'); + + const { getCredentials } = await import('./app/credentials.js'); + + let websocket_url; + let bosh_service_url; + + const { connectionManager, login, password } = await getCredentials(); + const priority = (await api.settings.get('priority')) || 0; + const omemo_default = (await api.settings.get('omemo_default')) || false; + + 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, + play_sounds: false, + priority, + prune_messages_above: 250, + // theme: 'classic', // there is no need for themes when using RS css. + view_mode: 'fullscreen', + websocket_url, + whitelisted_plugins: [ + 'converse-debug', + 'converse-desktop-credentials', + 'converse-desktop-trayicon', + 'converse-desktop-settings' + ], + omemo_default + }).catch(reason => { + console.error(reason); + api.app.quit(); + }); +})();