|
|
|
@ -3,6 +3,7 @@
|
|
|
|
|
/* |
|
|
|
|
Copyright 2016 Aviral Dasgupta |
|
|
|
|
Copyright 2016 OpenMarket Ltd |
|
|
|
|
Copyright 2018 New Vector Ltd |
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
|
you may not use this file except in compliance with the License. |
|
|
|
@ -21,44 +22,26 @@ import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
|
|
|
|
|
import dis from 'matrix-react-sdk/lib/dispatcher'; |
|
|
|
|
import { _t } from 'matrix-react-sdk/lib/languageHandler'; |
|
|
|
|
import Promise from 'bluebird'; |
|
|
|
|
import {remote, ipcRenderer, desktopCapturer} from 'electron'; |
|
|
|
|
import rageshake from 'matrix-react-sdk/lib/rageshake/rageshake'; |
|
|
|
|
|
|
|
|
|
remote.autoUpdater.on('update-downloaded', onUpdateDownloaded); |
|
|
|
|
|
|
|
|
|
// try to flush the rageshake logs to indexeddb before quit.
|
|
|
|
|
ipcRenderer.on('before-quit', function() { |
|
|
|
|
console.log('riot-desktop closing'); |
|
|
|
|
rageshake.flush(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
function onUpdateDownloaded(ev: Event, releaseNotes: string, ver: string, date: Date, updateURL: string) { |
|
|
|
|
dis.dispatch({ |
|
|
|
|
action: 'new_version', |
|
|
|
|
currentVersion: remote.app.getVersion(), |
|
|
|
|
newVersion: ver, |
|
|
|
|
releaseNotes: releaseNotes, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
const ipcRenderer = window.ipcRenderer; |
|
|
|
|
|
|
|
|
|
function platformFriendlyName(): string { |
|
|
|
|
console.log(window.process); |
|
|
|
|
switch (window.process.platform) { |
|
|
|
|
case 'darwin': |
|
|
|
|
return 'macOS'; |
|
|
|
|
case 'freebsd': |
|
|
|
|
return 'FreeBSD'; |
|
|
|
|
case 'openbsd': |
|
|
|
|
return 'OpenBSD'; |
|
|
|
|
case 'sunos': |
|
|
|
|
return 'SunOS'; |
|
|
|
|
case 'win32': |
|
|
|
|
return 'Windows'; |
|
|
|
|
default: |
|
|
|
|
// Sorry, Linux users: you get lumped into here,
|
|
|
|
|
// but only because Linux's capitalisation is
|
|
|
|
|
// normal. We do care about you.
|
|
|
|
|
return window.process.platform[0].toUpperCase() + window.process.platform.slice(1); |
|
|
|
|
// used to use window.process but the same info is available here
|
|
|
|
|
if (navigator.userAgent.indexOf('Macintosh')) { |
|
|
|
|
return 'macOS'; |
|
|
|
|
} else if (navigator.userAgent.indexOf('FreeBSD')) { |
|
|
|
|
return 'FreeBSD'; |
|
|
|
|
} else if (navigator.userAgent.indexOf('OpenBSD')) { |
|
|
|
|
return 'OpenBSD'; |
|
|
|
|
} else if (navigator.userAgent.indexOf('SunOS')) { |
|
|
|
|
return 'SunOS'; |
|
|
|
|
} else if (navigator.userAgent.indexOf('Windows')) { |
|
|
|
|
return 'Windows'; |
|
|
|
|
} else if (navigator.userAgent.indexOf('Linux')) { |
|
|
|
|
return 'Linux'; |
|
|
|
|
} else { |
|
|
|
|
return 'Unknown'; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -85,9 +68,11 @@ function getUpdateCheckStatus(status) {
|
|
|
|
|
export default class ElectronPlatform extends VectorBasePlatform { |
|
|
|
|
constructor() { |
|
|
|
|
super(); |
|
|
|
|
dis.register(_onAction); |
|
|
|
|
this.updatable = Boolean(remote.autoUpdater.getFeedURL()); |
|
|
|
|
|
|
|
|
|
this._pendingIpcCalls = {}; |
|
|
|
|
this._nextIpcCallId = 0; |
|
|
|
|
|
|
|
|
|
dis.register(_onAction); |
|
|
|
|
/* |
|
|
|
|
IPC Call `check_updates` returns: |
|
|
|
|
true if there is an update available |
|
|
|
@ -103,10 +88,28 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|
|
|
|
this.showUpdateCheck = false; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// try to flush the rageshake logs to indexeddb before quit.
|
|
|
|
|
ipcRenderer.on('before-quit', function() { |
|
|
|
|
console.log('riot-desktop closing'); |
|
|
|
|
rageshake.flush(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
ipcRenderer.on('ipcReply', this._onIpcReply.bind(this)); |
|
|
|
|
ipcRenderer.on('update-downloaded', this.onUpdateDownloaded.bind(this)); |
|
|
|
|
|
|
|
|
|
this.startUpdateCheck = this.startUpdateCheck.bind(this); |
|
|
|
|
this.stopUpdateCheck = this.stopUpdateCheck.bind(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async onUpdateDownloaded(ev, updateInfo) { |
|
|
|
|
dis.dispatch({ |
|
|
|
|
action: 'new_version', |
|
|
|
|
currentVersion: await this.getAppVersion(), |
|
|
|
|
newVersion: updateInfo, |
|
|
|
|
releaseNotes: updateInfo.releaseNotes, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getHumanReadableName(): string { |
|
|
|
|
return 'Electron Platform'; // no translation required: only used for analytics
|
|
|
|
|
} |
|
|
|
@ -133,7 +136,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|
|
|
|
// maybe we should pass basic styling (italics, bold, underline) through from MD
|
|
|
|
|
// we only have to strip out < and > as the spec doesn't include anything about things like &
|
|
|
|
|
// so we shouldn't assume that all implementations will treat those properly. Very basic tag parsing is done.
|
|
|
|
|
if (window.process.platform === 'linux') { |
|
|
|
|
if (navigator.userAgent.indexOf('Linux')) { |
|
|
|
|
msg = msg.replace(/</g, '<').replace(/>/g, '>'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -147,17 +150,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
notification.onclick = function() { |
|
|
|
|
notification.onclick = () => { |
|
|
|
|
dis.dispatch({ |
|
|
|
|
action: 'view_room', |
|
|
|
|
room_id: room.roomId, |
|
|
|
|
}); |
|
|
|
|
global.focus(); |
|
|
|
|
const win = remote.getCurrentWindow(); |
|
|
|
|
|
|
|
|
|
if (win.isMinimized()) win.restore(); |
|
|
|
|
else if (!win.isVisible()) win.show(); |
|
|
|
|
else win.focus(); |
|
|
|
|
this._ipcCall('focusWindow'); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return notification; |
|
|
|
@ -171,8 +170,25 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|
|
|
|
notif.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getAppVersion(): Promise<string> { |
|
|
|
|
return Promise.resolve(remote.app.getVersion()); |
|
|
|
|
async getAppVersion(): Promise<string> { |
|
|
|
|
return await this._ipcCall('getAppVersion'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
supportsAutoLaunch() { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async getAutoLaunchEnabled() { |
|
|
|
|
return await this._ipcCall('getAutoLaunchEnabled'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async setAutoLaunchEnabled(enabled) { |
|
|
|
|
return await this._ipcCall('setAutoLaunchEnabled', enabled); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async canSelfUpdate(): boolean { |
|
|
|
|
const feedUrl = await this._ipcCall('getUpdateFeedUrl'); |
|
|
|
|
return Boolean(feedUrl); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
startUpdateCheck() { |
|
|
|
@ -197,52 +213,43 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isElectron(): boolean { return true; } |
|
|
|
|
|
|
|
|
|
requestNotificationPermission(): Promise<string> { |
|
|
|
|
return Promise.resolve('granted'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
reload() { |
|
|
|
|
remote.getCurrentWebContents().reload(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* BEGIN copied and slightly-modified code |
|
|
|
|
* setupScreenSharingForIframe function from: |
|
|
|
|
* https://github.com/jitsi/jitsi-meet-electron-utils
|
|
|
|
|
* Copied directly here to avoid the need for a native electron module for |
|
|
|
|
* 'just a bit of JavaScript' |
|
|
|
|
* NOTE: Apache v2.0 licensed |
|
|
|
|
*/ |
|
|
|
|
setupScreenSharingForIframe(iframe: Object) { |
|
|
|
|
iframe.contentWindow.JitsiMeetElectron = { |
|
|
|
|
/** |
|
|
|
|
* Get sources available for screensharing. The callback is invoked |
|
|
|
|
* with an array of DesktopCapturerSources. |
|
|
|
|
* |
|
|
|
|
* @param {Function} callback - The success callback. |
|
|
|
|
* @param {Function} errorCallback - The callback for errors. |
|
|
|
|
* @param {Object} options - Configuration for getting sources. |
|
|
|
|
* @param {Array} options.types - Specify the desktop source types |
|
|
|
|
* to get, with valid sources being "window" and "screen". |
|
|
|
|
* @param {Object} options.thumbnailSize - Specify how big the |
|
|
|
|
* preview images for the sources should be. The valid keys are |
|
|
|
|
* height and width, e.g. { height: number, width: number}. By |
|
|
|
|
* default electron will return images with height and width of |
|
|
|
|
* 150px. |
|
|
|
|
*/ |
|
|
|
|
obtainDesktopStreams(callback, errorCallback, options = {}) { |
|
|
|
|
desktopCapturer.getSources(options, |
|
|
|
|
(error, sources) => { |
|
|
|
|
if (error) { |
|
|
|
|
errorCallback(error); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
callback(sources); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
// we used to remote to the main process to get it to
|
|
|
|
|
// reload the webcontents, but in practice this is unnecessary:
|
|
|
|
|
// the normal way works fine.
|
|
|
|
|
window.location.reload(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async _ipcCall(name, ...args) { |
|
|
|
|
const ipcCallId = ++this._nextIpcCallId; |
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
this._pendingIpcCalls[ipcCallId] = {resolve, reject}; |
|
|
|
|
window.ipcRenderer.send('ipcCall', {id: ipcCallId, name, args}); |
|
|
|
|
// Maybe add a timeout to these? Probably not necessary.
|
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_onIpcReply(ev, payload) { |
|
|
|
|
if (payload.id === undefined) { |
|
|
|
|
console.warn("Ignoring IPC reply with no ID"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this._pendingIpcCalls[payload.id] === undefined) { |
|
|
|
|
console.warn("Unknown IPC payload ID: " + payload.id); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const callbacks = this._pendingIpcCalls[payload.id]; |
|
|
|
|
delete this._pendingIpcCalls[payload.id]; |
|
|
|
|
if (payload.error) { |
|
|
|
|
callbacks.reject(payload.error); |
|
|
|
|
} else { |
|
|
|
|
callbacks.resolve(payload.reply); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* END of copied and slightly-modified code */ |
|
|
|
|
} |
|
|
|
|