aboutsummaryrefslogtreecommitdiffstats
path: root/src/stores/AppStore.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/stores/AppStore.js')
-rw-r--r--src/stores/AppStore.js84
1 files changed, 47 insertions, 37 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index dd4642d70..72c4b4d0b 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -1,21 +1,25 @@
1import { remote, ipcRenderer, shell } from 'electron'; 1import { remote, ipcRenderer, shell } from 'electron';
2import { action, computed, observable } from 'mobx'; 2import {
3 action, computed, observable, reaction,
4} from 'mobx';
3import moment from 'moment'; 5import moment from 'moment';
4import key from 'keymaster';
5import { getDoNotDisturb } from '@meetfranz/electron-notification-state'; 6import { getDoNotDisturb } from '@meetfranz/electron-notification-state';
6import AutoLaunch from 'auto-launch'; 7import AutoLaunch from 'auto-launch';
7import prettyBytes from 'pretty-bytes'; 8import prettyBytes from 'pretty-bytes';
9import ms from 'ms';
10import { URL } from 'url';
8 11
9import Store from './lib/Store'; 12import Store from './lib/Store';
10import Request from './lib/Request'; 13import Request from './lib/Request';
11import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; 14import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config';
12import { isMac, isLinux, isWindows } from '../environment'; 15import { isMac } from '../environment';
13import locales from '../i18n/translations'; 16import locales from '../i18n/translations';
14import { gaEvent } from '../lib/analytics'; 17import { gaEvent, gaPage, statsEvent } from '../lib/analytics';
15import { onVisibilityChange } from '../helpers/visibility-helper'; 18import { onVisibilityChange } from '../helpers/visibility-helper';
16import { getLocale } from '../helpers/i18n-helpers'; 19import { getLocale } from '../helpers/i18n-helpers';
17 20
18import { getServiceIdsFromPartitions, removeServicePartitionDirectory } from '../helpers/service-helpers.js'; 21import { getServiceIdsFromPartitions, removeServicePartitionDirectory } from '../helpers/service-helpers.js';
22import { isValidExternalURL } from '../helpers/url-helpers';
19 23
20const debug = require('debug')('Franz:AppStore'); 24const debug = require('debug')('Franz:AppStore');
21 25
@@ -63,6 +67,8 @@ export default class AppStore extends Store {
63 67
64 @observable isFocused = true; 68 @observable isFocused = true;
65 69
70 @observable nextAppReleaseVersion = null;
71
66 dictionaries = []; 72 dictionaries = [];
67 73
68 constructor(...args) { 74 constructor(...args) {
@@ -110,16 +116,16 @@ export default class AppStore extends Store {
110 // Check if system is muted 116 // Check if system is muted
111 // There are no events to subscribe so we need to poll everey 5s 117 // There are no events to subscribe so we need to poll everey 5s
112 this._systemDND(); 118 this._systemDND();
113 setInterval(() => this._systemDND(), 5000); 119 setInterval(() => this._systemDND(), ms('5s'));
114 120
115 // Check for updates once every 4 hours 121 // Check for updates once every 4 hours
116 setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); 122 setInterval(() => this._checkForUpdates(), CHECK_INTERVAL);
117 // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) 123 // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues)
118 setTimeout(() => this._checkForUpdates(), 30000); 124 setTimeout(() => this._checkForUpdates(), ms('30s'));
119 ipcRenderer.on('autoUpdate', (event, data) => { 125 ipcRenderer.on('autoUpdate', (event, data) => {
120 if (data.available) { 126 if (data.available) {
121 this.updateStatus = this.updateStatusTypes.AVAILABLE; 127 this.updateStatus = this.updateStatusTypes.AVAILABLE;
122 128 this.nextAppReleaseVersion = data.version;
123 if (isMac) { 129 if (isMac) {
124 app.dock.bounce(); 130 app.dock.bounce();
125 } 131 }
@@ -143,32 +149,14 @@ export default class AppStore extends Store {
143 149
144 // Handle deep linking (franz://) 150 // Handle deep linking (franz://)
145 ipcRenderer.on('navigateFromDeepLink', (event, data) => { 151 ipcRenderer.on('navigateFromDeepLink', (event, data) => {
146 const { url } = data; 152 debug('Navigate from deep link', data);
153 let { url } = data;
147 if (!url) return; 154 if (!url) return;
148 155
149 this.stores.router.push(data.url); 156 url = url.replace(/\/$/, '');
150 });
151
152 // Set active the next service
153 key(
154 '⌘+pagedown, ctrl+pagedown, ⌘+alt+right, ctrl+tab', () => {
155 this.actions.service.setActiveNext();
156 },
157 );
158 157
159 // Set active the prev service 158 this.stores.router.push(url);
160 key( 159 });
161 '⌘+pageup, ctrl+pageup, ⌘+alt+left, ctrl+shift+tab', () => {
162 this.actions.service.setActivePrev();
163 },
164 );
165
166 // Global Mute
167 key(
168 '⌘+shift+m ctrl+shift+m', () => {
169 this.actions.app.toggleMuteApp();
170 },
171 );
172 160
173 this.locale = this._getDefaultLocale(); 161 this.locale = this._getDefaultLocale();
174 162
@@ -181,6 +169,13 @@ export default class AppStore extends Store {
181 169
182 debug('Window is visible/focused', isVisible); 170 debug('Window is visible/focused', isVisible);
183 }); 171 });
172
173 // analytics autorun
174 reaction(() => this.stores.router.location.pathname, (pathname) => {
175 gaPage(pathname);
176 });
177
178 statsEvent('app-start');
184 } 179 }
185 180
186 @computed get cacheSize() { 181 @computed get cacheSize() {
@@ -193,7 +188,15 @@ export default class AppStore extends Store {
193 }) { 188 }) {
194 if (this.stores.settings.all.app.isAppMuted) return; 189 if (this.stores.settings.all.app.isAppMuted) return;
195 190
191 // TODO: is there a simple way to use blobs for notifications without storing them on disk?
192 if (options.icon.startsWith('blob:')) {
193 delete options.icon;
194 }
195
196 const notification = new window.Notification(title, options); 196 const notification = new window.Notification(title, options);
197
198 debug('New notification', title, options);
199
197 notification.onclick = (e) => { 200 notification.onclick = (e) => {
198 if (serviceId) { 201 if (serviceId) {
199 this.actions.service.sendIPCMessage({ 202 this.actions.service.sendIPCMessage({
@@ -203,12 +206,13 @@ export default class AppStore extends Store {
203 }); 206 });
204 207
205 this.actions.service.setActive({ serviceId }); 208 this.actions.service.setActive({ serviceId });
206 209 mainWindow.show();
207 if (isWindows) { 210 if (app.mainWindow.isMinimized()) {
208 mainWindow.restore(); 211 mainWindow.restore();
209 } else if (isLinux) {
210 mainWindow.show();
211 } 212 }
213 mainWindow.focus();
214
215 debug('Notification click handler');
212 } 216 }
213 }; 217 };
214 } 218 }
@@ -244,7 +248,14 @@ export default class AppStore extends Store {
244 } 248 }
245 249
246 @action _openExternalUrl({ url }) { 250 @action _openExternalUrl({ url }) {
247 shell.openExternal(url); 251 const parsedUrl = new URL(url);
252 debug('open external url', parsedUrl);
253
254 if (isValidExternalURL(url)) {
255 shell.openExternal(url);
256 }
257
258 gaEvent('External URL', 'open', parsedUrl.host);
248 } 259 }
249 260
250 @action _checkForUpdates() { 261 @action _checkForUpdates() {
@@ -268,7 +279,6 @@ export default class AppStore extends Store {
268 279
269 @action _muteApp({ isMuted, overrideSystemMute = true }) { 280 @action _muteApp({ isMuted, overrideSystemMute = true }) {
270 this.isSystemMuteOverridden = overrideSystemMute; 281 this.isSystemMuteOverridden = overrideSystemMute;
271
272 this.actions.settings.update({ 282 this.actions.settings.update({
273 type: 'app', 283 type: 'app',
274 data: { 284 data: {
@@ -305,7 +315,7 @@ export default class AppStore extends Store {
305 } else { 315 } else {
306 const deltaTime = moment().diff(this.timeOfflineStart); 316 const deltaTime = moment().diff(this.timeOfflineStart);
307 317
308 if (deltaTime > 30 * 60 * 1000) { 318 if (deltaTime > ms('30m')) {
309 this.actions.service.reloadAll(); 319 this.actions.service.reloadAll();
310 } 320 }
311 } 321 }