mirror of
https://github.com/SchildiChat/element-web.git
synced 2024-10-01 01:26:12 -04:00
Merge pull request #13756 from vector-im/t3chguy/toasts2
Convert platforms to Typescript
This commit is contained in:
commit
b4284b4c68
7
src/@types/global.d.ts
vendored
7
src/@types/global.d.ts
vendored
@ -32,3 +32,10 @@ declare global {
|
|||||||
InstallTrigger: any;
|
InstallTrigger: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add method which is missing from the node typing
|
||||||
|
declare module "url" {
|
||||||
|
interface Url {
|
||||||
|
format(): string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2016 Aviral Dasgupta
|
Copyright 2016 Aviral Dasgupta
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
@ -21,11 +19,20 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
|
import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
|
||||||
import BaseEventIndexManager from 'matrix-react-sdk/src/indexing/BaseEventIndexManager';
|
import BaseEventIndexManager, {
|
||||||
|
MatrixEvent,
|
||||||
|
MatrixProfile,
|
||||||
|
SearchResult,
|
||||||
|
CrawlerCheckpoint,
|
||||||
|
EventAndProfile,
|
||||||
|
SearchArgs,
|
||||||
|
IndexStats
|
||||||
|
} from 'matrix-react-sdk/src/indexing/BaseEventIndexManager';
|
||||||
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
||||||
import { _t, _td } from 'matrix-react-sdk/src/languageHandler';
|
import { _t, _td } from 'matrix-react-sdk/src/languageHandler';
|
||||||
import * as rageshake from 'matrix-react-sdk/src/rageshake/rageshake';
|
import * as rageshake from 'matrix-react-sdk/src/rageshake/rageshake';
|
||||||
import {MatrixClient} from "matrix-js-sdk";
|
import {MatrixClient} from "matrix-js-sdk/src/client";
|
||||||
|
import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
import Modal from "matrix-react-sdk/src/Modal";
|
import Modal from "matrix-react-sdk/src/Modal";
|
||||||
import InfoDialog from "matrix-react-sdk/src/components/views/dialogs/InfoDialog";
|
import InfoDialog from "matrix-react-sdk/src/components/views/dialogs/InfoDialog";
|
||||||
import Spinner from "matrix-react-sdk/src/components/views/elements/Spinner";
|
import Spinner from "matrix-react-sdk/src/components/views/elements/Spinner";
|
||||||
@ -34,6 +41,7 @@ import {Key} from "matrix-react-sdk/src/Keyboard";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {randomString} from "matrix-js-sdk/src/randomstring";
|
import {randomString} from "matrix-js-sdk/src/randomstring";
|
||||||
import {Action} from "matrix-react-sdk/src/dispatcher/actions";
|
import {Action} from "matrix-react-sdk/src/dispatcher/actions";
|
||||||
|
import { ActionPayload } from "matrix-react-sdk/src/dispatcher/payloads";
|
||||||
|
|
||||||
const ipcRenderer = window.ipcRenderer;
|
const ipcRenderer = window.ipcRenderer;
|
||||||
const isMac = navigator.platform.toUpperCase().includes('MAC');
|
const isMac = navigator.platform.toUpperCase().includes('MAC');
|
||||||
@ -57,7 +65,7 @@ function platformFriendlyName(): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onAction(payload: Object) {
|
function _onAction(payload: ActionPayload) {
|
||||||
// Whitelist payload actions, no point sending most across
|
// Whitelist payload actions, no point sending most across
|
||||||
if (['call_state'].includes(payload.action)) {
|
if (['call_state'].includes(payload.action)) {
|
||||||
ipcRenderer.send('app_onAction', payload);
|
ipcRenderer.send('app_onAction', payload);
|
||||||
@ -77,53 +85,60 @@ function getUpdateCheckStatus(status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IPCPayload {
|
||||||
|
id?: number;
|
||||||
|
error?: string;
|
||||||
|
reply?: any;
|
||||||
|
}
|
||||||
|
|
||||||
class SeshatIndexManager extends BaseEventIndexManager {
|
class SeshatIndexManager extends BaseEventIndexManager {
|
||||||
|
private pendingIpcCalls: Record<number, { resolve, reject }> = {};
|
||||||
|
private nextIpcCallId: number = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._pendingIpcCalls = {};
|
ipcRenderer.on('seshatReply', this._onIpcReply);
|
||||||
this._nextIpcCallId = 0;
|
|
||||||
ipcRenderer.on('seshatReply', this._onIpcReply.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _ipcCall(name: string, ...args: []): Promise<{}> {
|
async _ipcCall(name: string, ...args: any[]): Promise<any> {
|
||||||
// TODO this should be moved into the preload.js file.
|
// TODO this should be moved into the preload.js file.
|
||||||
const ipcCallId = ++this._nextIpcCallId;
|
const ipcCallId = ++this.nextIpcCallId;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._pendingIpcCalls[ipcCallId] = {resolve, reject};
|
this.pendingIpcCalls[ipcCallId] = {resolve, reject};
|
||||||
window.ipcRenderer.send('seshat', {id: ipcCallId, name, args});
|
window.ipcRenderer.send('seshat', {id: ipcCallId, name, args});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onIpcReply(ev: {}, payload: {}) {
|
_onIpcReply = (ev: {}, payload: IPCPayload) => {
|
||||||
if (payload.id === undefined) {
|
if (payload.id === undefined) {
|
||||||
console.warn("Ignoring IPC reply with no ID");
|
console.warn("Ignoring IPC reply with no ID");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._pendingIpcCalls[payload.id] === undefined) {
|
if (this.pendingIpcCalls[payload.id] === undefined) {
|
||||||
console.warn("Unknown IPC payload ID: " + payload.id);
|
console.warn("Unknown IPC payload ID: " + payload.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const callbacks = this._pendingIpcCalls[payload.id];
|
const callbacks = this.pendingIpcCalls[payload.id];
|
||||||
delete this._pendingIpcCalls[payload.id];
|
delete this.pendingIpcCalls[payload.id];
|
||||||
if (payload.error) {
|
if (payload.error) {
|
||||||
callbacks.reject(payload.error);
|
callbacks.reject(payload.error);
|
||||||
} else {
|
} else {
|
||||||
callbacks.resolve(payload.reply);
|
callbacks.resolve(payload.reply);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async supportsEventIndexing(): Promise<boolean> {
|
async supportsEventIndexing(): Promise<boolean> {
|
||||||
return this._ipcCall('supportsEventIndexing');
|
return this._ipcCall('supportsEventIndexing');
|
||||||
}
|
}
|
||||||
|
|
||||||
async initEventIndex(): Promise<> {
|
async initEventIndex(): Promise<void> {
|
||||||
return this._ipcCall('initEventIndex');
|
return this._ipcCall('initEventIndex');
|
||||||
}
|
}
|
||||||
|
|
||||||
async addEventToIndex(ev: MatrixEvent, profile: MatrixProfile): Promise<> {
|
async addEventToIndex(ev: MatrixEvent, profile: MatrixProfile): Promise<void> {
|
||||||
return this._ipcCall('addEventToIndex', ev, profile);
|
return this._ipcCall('addEventToIndex', ev, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,27 +150,27 @@ class SeshatIndexManager extends BaseEventIndexManager {
|
|||||||
return this._ipcCall('isEventIndexEmpty');
|
return this._ipcCall('isEventIndexEmpty');
|
||||||
}
|
}
|
||||||
|
|
||||||
async commitLiveEvents(): Promise<> {
|
async commitLiveEvents(): Promise<void> {
|
||||||
return this._ipcCall('commitLiveEvents');
|
return this._ipcCall('commitLiveEvents');
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchEventIndex(searchConfig: SearchConfig): Promise<SearchResult> {
|
async searchEventIndex(searchConfig: SearchArgs): Promise<SearchResult> {
|
||||||
return this._ipcCall('searchEventIndex', searchConfig);
|
return this._ipcCall('searchEventIndex', searchConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addHistoricEvents(
|
async addHistoricEvents(
|
||||||
events: [HistoricEvent],
|
events: [EventAndProfile],
|
||||||
checkpoint: CrawlerCheckpoint | null,
|
checkpoint: CrawlerCheckpoint | null,
|
||||||
oldCheckpoint: CrawlerCheckpoint | null,
|
oldCheckpoint: CrawlerCheckpoint | null,
|
||||||
): Promise<> {
|
): Promise<boolean> {
|
||||||
return this._ipcCall('addHistoricEvents', events, checkpoint, oldCheckpoint);
|
return this._ipcCall('addHistoricEvents', events, checkpoint, oldCheckpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> {
|
async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
|
||||||
return this._ipcCall('addCrawlerCheckpoint', checkpoint);
|
return this._ipcCall('addCrawlerCheckpoint', checkpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<> {
|
async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
|
||||||
return this._ipcCall('removeCrawlerCheckpoint', checkpoint);
|
return this._ipcCall('removeCrawlerCheckpoint', checkpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,27 +182,29 @@ class SeshatIndexManager extends BaseEventIndexManager {
|
|||||||
return this._ipcCall('loadCheckpoints');
|
return this._ipcCall('loadCheckpoints');
|
||||||
}
|
}
|
||||||
|
|
||||||
async closeEventIndex(): Promise<> {
|
async closeEventIndex(): Promise<void> {
|
||||||
return this._ipcCall('closeEventIndex');
|
return this._ipcCall('closeEventIndex');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStats(): Promise<> {
|
async getStats(): Promise<IndexStats> {
|
||||||
return this._ipcCall('getStats');
|
return this._ipcCall('getStats');
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteEventIndex(): Promise<> {
|
async deleteEventIndex(): Promise<void> {
|
||||||
return this._ipcCall('deleteEventIndex');
|
return this._ipcCall('deleteEventIndex');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ElectronPlatform extends VectorBasePlatform {
|
export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
|
private eventIndexManager: BaseEventIndexManager = new SeshatIndexManager();
|
||||||
|
private pendingIpcCalls: Record<number, { resolve, reject }> = {};
|
||||||
|
private nextIpcCallId: number = 0;
|
||||||
|
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
|
||||||
|
private ssoID: string = randomString(32);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._pendingIpcCalls = {};
|
|
||||||
this._nextIpcCallId = 0;
|
|
||||||
this.eventIndexManager = new SeshatIndexManager();
|
|
||||||
|
|
||||||
dis.register(_onAction);
|
dis.register(_onAction);
|
||||||
/*
|
/*
|
||||||
IPC Call `check_updates` returns:
|
IPC Call `check_updates` returns:
|
||||||
@ -217,9 +234,6 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
dis.fire(Action.ViewUserSettings);
|
dis.fire(Action.ViewUserSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
|
||||||
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
|
|
||||||
|
|
||||||
// register OS-specific shortcuts
|
// register OS-specific shortcuts
|
||||||
if (isMac) {
|
if (isMac) {
|
||||||
registerShortcut(Categories.NAVIGATION, {
|
registerShortcut(Categories.NAVIGATION, {
|
||||||
@ -253,8 +267,6 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
|
|
||||||
this.ssoID = randomString(32);
|
|
||||||
this._ipcCall("startSSOFlow", this.ssoID);
|
this._ipcCall("startSSOFlow", this.ssoID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +302,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification {
|
displayNotification(title: string, msg: string, avatarUrl: string, room: Room): Notification {
|
||||||
// GNOME notification spec parses HTML tags for styling...
|
// GNOME notification spec parses HTML tags for styling...
|
||||||
// Electron Docs state all supported linux notification systems follow this markup spec
|
// Electron Docs state all supported linux notification systems follow this markup spec
|
||||||
// https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux
|
// https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux
|
||||||
@ -307,14 +319,14 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
silent: true, // we play our own sounds
|
silent: true, // we play our own sounds
|
||||||
};
|
};
|
||||||
if (avatarUrl) notifBody['icon'] = avatarUrl;
|
if (avatarUrl) notifBody['icon'] = avatarUrl;
|
||||||
const notification = new global.Notification(title, notifBody);
|
const notification = new window.Notification(title, notifBody);
|
||||||
|
|
||||||
notification.onclick = () => {
|
notification.onclick = () => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
global.focus();
|
window.focus();
|
||||||
this._ipcCall('focusWindow');
|
this._ipcCall('focusWindow');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -337,11 +349,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAutoLaunchEnabled(): boolean {
|
async getAutoLaunchEnabled(): Promise<boolean> {
|
||||||
return this._ipcCall('getAutoLaunchEnabled');
|
return this._ipcCall('getAutoLaunchEnabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
async setAutoLaunchEnabled(enabled: boolean): void {
|
async setAutoLaunchEnabled(enabled: boolean): Promise<void> {
|
||||||
return this._ipcCall('setAutoLaunchEnabled', enabled);
|
return this._ipcCall('setAutoLaunchEnabled', enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,11 +362,11 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return !isMac;
|
return !isMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAutoHideMenuBarEnabled(): boolean {
|
async getAutoHideMenuBarEnabled(): Promise<boolean> {
|
||||||
return this._ipcCall('getAutoHideMenuBarEnabled');
|
return this._ipcCall('getAutoHideMenuBarEnabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
async setAutoHideMenuBarEnabled(enabled: boolean): void {
|
async setAutoHideMenuBarEnabled(enabled: boolean): Promise<void> {
|
||||||
return this._ipcCall('setAutoHideMenuBarEnabled', enabled);
|
return this._ipcCall('setAutoHideMenuBarEnabled', enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,25 +375,25 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return !isMac;
|
return !isMac;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMinimizeToTrayEnabled(): boolean {
|
async getMinimizeToTrayEnabled(): Promise<boolean> {
|
||||||
return this._ipcCall('getMinimizeToTrayEnabled');
|
return this._ipcCall('getMinimizeToTrayEnabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
async setMinimizeToTrayEnabled(enabled: boolean): void {
|
async setMinimizeToTrayEnabled(enabled: boolean): Promise<void> {
|
||||||
return this._ipcCall('setMinimizeToTrayEnabled', enabled);
|
return this._ipcCall('setMinimizeToTrayEnabled', enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
async canSelfUpdate(): boolean {
|
async canSelfUpdate(): Promise<boolean> {
|
||||||
const feedUrl = await this._ipcCall('getUpdateFeedUrl');
|
const feedUrl = await this._ipcCall('getUpdateFeedUrl');
|
||||||
return Boolean(feedUrl);
|
return Boolean(feedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
startUpdateCheck() {
|
startUpdateCheck = () => {
|
||||||
if (this.showUpdateCheck) return;
|
if (this.showUpdateCheck) return;
|
||||||
super.startUpdateCheck();
|
super.startUpdateCheck();
|
||||||
|
|
||||||
ipcRenderer.send('check_updates');
|
ipcRenderer.send('check_updates');
|
||||||
}
|
};
|
||||||
|
|
||||||
installUpdate() {
|
installUpdate() {
|
||||||
// IPC to the main process to install the update, since quitAndInstall
|
// IPC to the main process to install the update, since quitAndInstall
|
||||||
@ -394,7 +406,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return _t('Riot Desktop (%(platformName)s)', { platformName: platformFriendlyName() });
|
return _t('Riot Desktop (%(platformName)s)', { platformName: platformFriendlyName() });
|
||||||
}
|
}
|
||||||
|
|
||||||
screenCaptureErrorString(): ?string {
|
screenCaptureErrorString(): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,10 +421,10 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
window.location.reload(false);
|
window.location.reload(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _ipcCall(name, ...args) {
|
async _ipcCall(name: string, ...args: any[]): Promise<any> {
|
||||||
const ipcCallId = ++this._nextIpcCallId;
|
const ipcCallId = ++this.nextIpcCallId;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._pendingIpcCalls[ipcCallId] = {resolve, reject};
|
this.pendingIpcCalls[ipcCallId] = {resolve, reject};
|
||||||
window.ipcRenderer.send('ipcCall', {id: ipcCallId, name, args});
|
window.ipcRenderer.send('ipcCall', {id: ipcCallId, name, args});
|
||||||
// Maybe add a timeout to these? Probably not necessary.
|
// Maybe add a timeout to these? Probably not necessary.
|
||||||
});
|
});
|
||||||
@ -424,13 +436,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._pendingIpcCalls[payload.id] === undefined) {
|
if (this.pendingIpcCalls[payload.id] === undefined) {
|
||||||
console.warn("Unknown IPC payload ID: " + payload.id);
|
console.warn("Unknown IPC payload ID: " + payload.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const callbacks = this._pendingIpcCalls[payload.id];
|
const callbacks = this.pendingIpcCalls[payload.id];
|
||||||
delete this._pendingIpcCalls[payload.id];
|
delete this.pendingIpcCalls[payload.id];
|
||||||
if (payload.error) {
|
if (payload.error) {
|
||||||
callbacks.reject(payload.error);
|
callbacks.reject(payload.error);
|
||||||
} else {
|
} else {
|
@ -1,9 +1,7 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2016 Aviral Dasgupta
|
Copyright 2016 Aviral Dasgupta
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018, 2020 New Vector Ltd
|
||||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -24,7 +22,7 @@ import { _t } from 'matrix-react-sdk/src/languageHandler';
|
|||||||
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
||||||
import {getVectorConfig} from "../getconfig";
|
import {getVectorConfig} from "../getconfig";
|
||||||
|
|
||||||
import Favico from '../../favicon';
|
import Favicon from "../../favicon";
|
||||||
|
|
||||||
export const updateCheckStatusEnum = {
|
export const updateCheckStatusEnum = {
|
||||||
CHECKING: 'CHECKING',
|
CHECKING: 'CHECKING',
|
||||||
@ -37,14 +35,9 @@ export const updateCheckStatusEnum = {
|
|||||||
/**
|
/**
|
||||||
* Vector-specific extensions to the BasePlatform template
|
* Vector-specific extensions to the BasePlatform template
|
||||||
*/
|
*/
|
||||||
export default class VectorBasePlatform extends BasePlatform {
|
export default abstract class VectorBasePlatform extends BasePlatform {
|
||||||
constructor() {
|
protected showUpdateCheck: boolean = false;
|
||||||
super();
|
protected _favicon: Favicon;
|
||||||
|
|
||||||
this.showUpdateCheck = false;
|
|
||||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
|
||||||
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getConfig(): Promise<{}> {
|
async getConfig(): Promise<{}> {
|
||||||
return getVectorConfig();
|
return getVectorConfig();
|
||||||
@ -55,40 +48,27 @@ export default class VectorBasePlatform extends BasePlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay creating the `Favico` instance until first use (on the first notification) as
|
* Delay creating the `Favicon` instance until first use (on the first notification) as
|
||||||
* it uses canvas, which can trigger a permission prompt in Firefox's resist
|
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
|
||||||
* fingerprinting mode.
|
|
||||||
* See https://github.com/vector-im/riot-web/issues/9605.
|
* See https://github.com/vector-im/riot-web/issues/9605.
|
||||||
*/
|
*/
|
||||||
get favicon() {
|
get favicon() {
|
||||||
if (this._favicon) {
|
if (this._favicon) {
|
||||||
return this._favicon;
|
return this._favicon;
|
||||||
}
|
}
|
||||||
// The 'animations' are really low framerate and look terrible.
|
return this._favicon = new Favicon();
|
||||||
// Also it re-starts the animation every time you set the badge,
|
|
||||||
// and we set the state each time, even if the value hasn't changed,
|
|
||||||
// so we'd need to fix that if enabling the animation.
|
|
||||||
this._favicon = new Favico({ animation: 'none' });
|
|
||||||
return this._favicon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFavicon() {
|
_updateFavicon() {
|
||||||
try {
|
let bgColor = "#d00";
|
||||||
// This needs to be in in a try block as it will throw
|
let notif: string | number = this.notificationCount;
|
||||||
// if there are more than 100 badge count changes in
|
|
||||||
// its internal queue
|
|
||||||
let bgColor = "#d00";
|
|
||||||
let notif = this.notificationCount;
|
|
||||||
|
|
||||||
if (this.errorDidOccur) {
|
if (this.errorDidOccur) {
|
||||||
notif = notif || "×";
|
notif = notif || "×";
|
||||||
bgColor = "#f00";
|
bgColor = "#f00";
|
||||||
}
|
|
||||||
|
|
||||||
this.favicon.badge(notif, { bgColor });
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(`Failed to set badge count: ${e.message}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.favicon.badge(notif, { bgColor });
|
||||||
}
|
}
|
||||||
|
|
||||||
setNotificationCount(count: number) {
|
setNotificationCount(count: number) {
|
||||||
@ -112,25 +92,25 @@ export default class VectorBasePlatform extends BasePlatform {
|
|||||||
/**
|
/**
|
||||||
* Whether we can call checkForUpdate on this platform build
|
* Whether we can call checkForUpdate on this platform build
|
||||||
*/
|
*/
|
||||||
async canSelfUpdate(): boolean {
|
async canSelfUpdate(): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
startUpdateCheck() {
|
startUpdateCheck = () => {
|
||||||
this.showUpdateCheck = true;
|
this.showUpdateCheck = true;
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'check_updates',
|
action: 'check_updates',
|
||||||
value: { status: updateCheckStatusEnum.CHECKING },
|
value: { status: updateCheckStatusEnum.CHECKING },
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
stopUpdateCheck() {
|
stopUpdateCheck = () => {
|
||||||
this.showUpdateCheck = false;
|
this.showUpdateCheck = false;
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'check_updates',
|
action: 'check_updates',
|
||||||
value: false,
|
value: false,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
getUpdateCheckStatusEnum() {
|
getUpdateCheckStatusEnum() {
|
||||||
return updateCheckStatusEnum;
|
return updateCheckStatusEnum;
|
@ -1,5 +1,3 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2016 Aviral Dasgupta
|
Copyright 2016 Aviral Dasgupta
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
@ -22,6 +20,7 @@ import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
|
|||||||
import request from 'browser-request';
|
import request from 'browser-request';
|
||||||
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
||||||
import { _t } from 'matrix-react-sdk/src/languageHandler';
|
import { _t } from 'matrix-react-sdk/src/languageHandler';
|
||||||
|
import {Room} from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import UAParser from 'ua-parser-js';
|
import UAParser from 'ua-parser-js';
|
||||||
@ -29,13 +28,7 @@ import UAParser from 'ua-parser-js';
|
|||||||
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
||||||
|
|
||||||
export default class WebPlatform extends VectorBasePlatform {
|
export default class WebPlatform extends VectorBasePlatform {
|
||||||
constructor() {
|
private runningVersion: string = null;
|
||||||
super();
|
|
||||||
this.runningVersion = null;
|
|
||||||
|
|
||||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
|
||||||
this.stopUpdateCheck = this.stopUpdateCheck.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
getHumanReadableName(): string {
|
getHumanReadableName(): string {
|
||||||
return 'Web Platform'; // no translation required: only used for analytics
|
return 'Web Platform'; // no translation required: only used for analytics
|
||||||
@ -46,7 +39,7 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
* notifications, otherwise false.
|
* notifications, otherwise false.
|
||||||
*/
|
*/
|
||||||
supportsNotifications(): boolean {
|
supportsNotifications(): boolean {
|
||||||
return Boolean(global.Notification);
|
return Boolean(window.Notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,7 +47,7 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
* to display notifications. Otherwise false.
|
* to display notifications. Otherwise false.
|
||||||
*/
|
*/
|
||||||
maySendNotifications(): boolean {
|
maySendNotifications(): boolean {
|
||||||
return global.Notification.permission === 'granted';
|
return window.Notification.permission === 'granted';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,27 +62,27 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
// promise, but this is only supported in Chrome 46
|
// promise, but this is only supported in Chrome 46
|
||||||
// and Firefox 47, so adapt the callback API.
|
// and Firefox 47, so adapt the callback API.
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
global.Notification.requestPermission((result) => {
|
window.Notification.requestPermission((result) => {
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
displayNotification(title: string, msg: string, avatarUrl: string, room: Object) {
|
displayNotification(title: string, msg: string, avatarUrl: string, room: Room) {
|
||||||
const notifBody = {
|
const notifBody = {
|
||||||
body: msg,
|
body: msg,
|
||||||
tag: "vector",
|
tag: "vector",
|
||||||
silent: true, // we play our own sounds
|
silent: true, // we play our own sounds
|
||||||
};
|
};
|
||||||
if (avatarUrl) notifBody['icon'] = avatarUrl;
|
if (avatarUrl) notifBody['icon'] = avatarUrl;
|
||||||
const notification = new global.Notification(title, notifBody);
|
const notification = new window.Notification(title, notifBody);
|
||||||
|
|
||||||
notification.onclick = function() {
|
notification.onclick = function() {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
global.focus();
|
window.focus();
|
||||||
notification.close();
|
notification.close();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -131,14 +124,14 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
|
|
||||||
startUpdater() {
|
startUpdater() {
|
||||||
this.pollForUpdate();
|
this.pollForUpdate();
|
||||||
setInterval(this.pollForUpdate.bind(this), POKE_RATE_MS);
|
setInterval(this.pollForUpdate, POKE_RATE_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
async canSelfUpdate(): boolean {
|
async canSelfUpdate(): Promise<boolean> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pollForUpdate() {
|
pollForUpdate = () => {
|
||||||
return this._getVersion().then((ver) => {
|
return this._getVersion().then((ver) => {
|
||||||
if (this.runningVersion === null) {
|
if (this.runningVersion === null) {
|
||||||
this.runningVersion = ver;
|
this.runningVersion = ver;
|
||||||
@ -159,9 +152,9 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
detail: err.message || err.status ? err.status.toString() : 'Unknown Error',
|
detail: err.message || err.status ? err.status.toString() : 'Unknown Error',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
startUpdateCheck() {
|
startUpdateCheck = () => {
|
||||||
if (this.showUpdateCheck) return;
|
if (this.showUpdateCheck) return;
|
||||||
super.startUpdateCheck();
|
super.startUpdateCheck();
|
||||||
this.pollForUpdate().then((updateState) => {
|
this.pollForUpdate().then((updateState) => {
|
||||||
@ -172,7 +165,7 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
value: updateState,
|
value: updateState,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
installUpdate() {
|
installUpdate() {
|
||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
@ -204,9 +197,9 @@ export default class WebPlatform extends VectorBasePlatform {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
screenCaptureErrorString(): ?string {
|
screenCaptureErrorString(): string | null {
|
||||||
// it won't work at all if you're not on HTTPS so whine whine whine
|
// it won't work at all if you're not on HTTPS so whine whine whine
|
||||||
if (!global.window || global.window.location.protocol !== "https:") {
|
if (window.location.protocol !== "https:") {
|
||||||
return _t("You need to be using HTTPS to place a screen-sharing call.");
|
return _t("You need to be using HTTPS to place a screen-sharing call.");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
Loading…
Reference in New Issue
Block a user