diff --git a/package.json b/package.json index 3daddc2c2..e9b91432c 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "classnames": "^2.1.2", "draft-js": "^0.8.1", "extract-text-webpack-plugin": "^0.9.1", + "favico.js": "^0.3.10", "filesize": "^3.1.2", "flux": "~2.0.3", "gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279", diff --git a/src/vector/index.js b/src/vector/index.js index 58d579fdf..f260ac01f 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -47,6 +47,7 @@ if (process.env.NODE_ENV !== 'production') { var RunModernizrTests = require("./modernizr"); // this side-effects a global var ReactDOM = require("react-dom"); var sdk = require("matrix-react-sdk"); +var PlatformPeg = require("matrix-react-sdk/lib/PlatformPeg"); sdk.loadSkin(require('../component-index')); var VectorConferenceHandler = require('../VectorConferenceHandler'); var UpdateChecker = require("./updater"); @@ -57,6 +58,7 @@ import UAParser from 'ua-parser-js'; import url from 'url'; import {parseQs, parseQsFromFragment} from './url_utils'; +import Platform from './platform'; var lastLocationHashSet = null; @@ -210,6 +212,9 @@ async function loadApp() { const fragparts = parseQsFromFragment(window.location); const params = parseQs(window.location); + // set the platform for react sdk (our Platform object automatically picks the right one) + PlatformPeg.set(new Platform()); + // don't try to redirect to the native apps if we're // verifying a 3pid const preventRedirect = Boolean(fragparts.params.client_secret); diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js new file mode 100644 index 000000000..7ef2b6b8a --- /dev/null +++ b/src/vector/platform/WebPlatform.js @@ -0,0 +1,91 @@ +// @flow + +/* +Copyright 2016 Aviral Dasgupta and OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import BasePlatform from 'matrix-react-sdk/lib/BasePlatform'; +import Favico from 'favico.js'; +import dis from 'matrix-react-sdk/lib/dispatcher.js'; +import q from 'q'; + +export default class WebPlatform extends BasePlatform { + constructor() { + super(); + // The 'animations' are really low framerate and look terrible. + // Also it re-starts the animationb 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'}); + this._updateFavicon(); + } + + _updateFavicon() { + try { + // This needs to be in in a try block as it will throw + // if there are more than 100 badge count changes in + // its internal queue + let bgColor = "#d00", + notif = this.notificationCount; + + if (this.errorDidOccur) { + notif = notif || "×"; + bgColor = "#f00"; + } + + this.favicon.badge(notif, { + bgColor: bgColor + }); + } catch (e) { + console.warn(`Failed to set badge count: ${e.message}`); + } + } + + setNotificationCount(count: number) { + super.setNotificationCount(count); + this._updateFavicon(); + } + + setErrorStatus(errorDidOccur: boolean) { + super.setErrorStatus(errorDidOccur); + this._updateFavicon(); + } + + displayNotification(title: string, msg: string, avatarUrl: string) { + const notification = new global.Notification( + title, + { + body: msg, + icon: avatarUrl, + tag: "vector", + silent: true, // we play our own sounds + } + ); + + notification.onclick = function() { + dis.dispatch({ + action: 'view_room', + room_id: room.roomId + }); + global.focus(); + }; + + // Chrome only dismisses notifications after 20s, which + // is waaaaay too long + global.setTimeout(function() { + notification.close(); + }, 5 * 1000); + } +} diff --git a/src/vector/platform/index.js b/src/vector/platform/index.js new file mode 100644 index 000000000..c0f17ae99 --- /dev/null +++ b/src/vector/platform/index.js @@ -0,0 +1,23 @@ +// @flow + +/* +Copyright 2016 Aviral Dasgupta and OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import WebPlatform from './WebPlatform'; + +let Platform = WebPlatform; + +export default Platform;