diff options
-rw-r--r-- | .github/ISSUE_TEMPLATE.md | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 30 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | electron-builder.yml | 2 | ||||
-rw-r--r-- | package.json | 5 | ||||
-rw-r--r-- | src/api/server/ServerApi.js | 17 | ||||
-rw-r--r-- | src/app.js | 4 | ||||
-rw-r--r-- | src/components/settings/services/EditServiceForm.js | 6 | ||||
-rw-r--r-- | src/environment.js | 11 | ||||
-rw-r--r-- | src/index.js | 34 | ||||
-rw-r--r-- | src/lib/Menu.js | 5 | ||||
-rw-r--r-- | src/models/Recipe.js | 19 | ||||
-rw-r--r-- | src/models/Service.js | 7 | ||||
-rw-r--r-- | src/stores/AppStore.js | 69 | ||||
-rw-r--r-- | src/webview/notifications.js | 41 | ||||
-rw-r--r-- | yarn.lock | 38 |
16 files changed, 176 insertions, 117 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4ef48f240..c11a2994f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md | |||
@@ -1,5 +1,7 @@ | |||
1 | <!--- Provide a general summary of the issue in the Title above --> | 1 | <!--- Provide a general summary of the issue in the Title above --> |
2 | 2 | ||
3 | <!-- This repository is only for the Franz client. Please use this form ( https://adlk.typeform.com/to/Bj7vGq ) for service requests or check out the guide ( https://github.com/meetfranz/plugins ) to create your own service integration. --> | ||
4 | |||
3 | <!--- If you want to propose a feature, use this template: https://raw.githubusercontent.com/meetfranz/franz/master/.github/FEATURE_PROPOSAL_TEMPLATE.md --> | 5 | <!--- If you want to propose a feature, use this template: https://raw.githubusercontent.com/meetfranz/franz/master/.github/FEATURE_PROPOSAL_TEMPLATE.md --> |
4 | 6 | ||
5 | ### Expected Behavior | 7 | ### Expected Behavior |
diff --git a/CHANGELOG.md b/CHANGELOG.md index e6551ed51..024afe93c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -1,3 +1,33 @@ | |||
1 | <a name="5.0.0-beta.13"></a> | ||
2 | # [5.0.0-beta.13](https://github.com/meetfranz/franz/compare/v5.0.0-beta.12...v5.0.0-beta.13) (2017-11-06) | ||
3 | |||
4 | ### Bug Fixes | ||
5 | |||
6 | * **Windows:** Fix issue with multiple close handlers that prevent the app from quitting ([eea593e](https://github.com/meetfranz/franz/commit/eea593e)) | ||
7 | |||
8 | |||
9 | <a name="5.0.0-beta.12"></a> | ||
10 | # [5.0.0-beta.12](https://github.com/meetfranz/franz/compare/v5.0.0-beta.11...v5.0.0-beta.12) (2017-11-05) | ||
11 | |||
12 | ### Features | ||
13 | |||
14 | * **Menu:** Add "About Franz" Menu item to Windows/Linux ([a21b770](https://github.com/meetfranz/franz/commit/a21b770)) | ||
15 | * **Menu:** Add menu item to toggle (service) dev tools ([e8da383](https://github.com/meetfranz/franz/commit/e8da383)) | ||
16 | * **Translation:** Add italian translation ([ab348cc](https://github.com/meetfranz/franz/commit/ab348cc)) ([dnlup](https://github.com/dnlup)) | ||
17 | |||
18 | |||
19 | ### Bug Fixes | ||
20 | |||
21 | * **App:** Add checks to service url validation to prevent app freeze ([db8515f](https://github.com/meetfranz/franz/commit/db8515f)) | ||
22 | * **macOS:** Fix disable launch Franz on start ([34bba09](https://github.com/meetfranz/franz/commit/34bba09)) | ||
23 | * **Windows:** Launch Franz on start when selected ([34bba09](https://github.com/meetfranz/franz/commit/34bba09)) | ||
24 | * **Onboarding:** Fix issue with import of on-premise services ([7c7d27d](https://github.com/meetfranz/franz/commit/7c7d27d)) | ||
25 | * **Shortcuts:** Flip shortcut to navigate to next/previous service ([37d5923](https://github.com/meetfranz/franz/commit/37d5923)) | ||
26 | * **Windows:** Open Window when app is pinned to taskbar and minimized to system tray ([777814a](https://github.com/meetfranz/franz/commit/777814a)) | ||
27 | * **Recipes:** Recipe developers don't need Premium Supporter Account for debugging ([7a9947a](https://github.com/meetfranz/franz/commit/7a9947a)), closes [#23](https://github.com/meetfranz/franz/issues/23) | ||
28 | |||
29 | |||
30 | |||
1 | <a name="5.0.0-beta.11"></a> | 31 | <a name="5.0.0-beta.11"></a> |
2 | # [5.0.0-beta.11](https://github.com/meetfranz/franz/compare/v5.0.0-beta.10...v5.0.0-beta.11) (2017-10-24) | 32 | # [5.0.0-beta.11](https://github.com/meetfranz/franz/compare/v5.0.0-beta.10...v5.0.0-beta.11) (2017-10-24) |
3 | 33 | ||
@@ -9,6 +9,9 @@ | |||
9 | 9 | ||
10 | Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more. | 10 | Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more. |
11 | 11 | ||
12 | ## [Download Franz](https://www.meetfranz.com) | ||
13 | 👉 www.meetfranz.com | ||
14 | |||
12 | 15 | ||
13 | ## Development | 16 | ## Development |
14 | 17 | ||
diff --git a/electron-builder.yml b/electron-builder.yml index 0a01a03d8..3f7ad1e85 100644 --- a/electron-builder.yml +++ b/electron-builder.yml | |||
@@ -29,5 +29,5 @@ linux: | |||
29 | - target: deb | 29 | - target: deb |
30 | 30 | ||
31 | nsis: | 31 | nsis: |
32 | perMachine: true | 32 | perMachine: false |
33 | oneClick: true | 33 | oneClick: true |
diff --git a/package.json b/package.json index dcb05bf6a..9b56cdf27 100644 --- a/package.json +++ b/package.json | |||
@@ -2,7 +2,7 @@ | |||
2 | "name": "franz", | 2 | "name": "franz", |
3 | "productName": "Franz", | 3 | "productName": "Franz", |
4 | "appId": "com.meetfranz.franz", | 4 | "appId": "com.meetfranz.franz", |
5 | "version": "5.0.0-beta.11", | 5 | "version": "5.0.0-beta.13", |
6 | "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", | 6 | "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", |
7 | "copyright": "adlk x franz - Stefan Malzner", | 7 | "copyright": "adlk x franz - Stefan Malzner", |
8 | "main": "index.js", | 8 | "main": "index.js", |
@@ -27,12 +27,13 @@ | |||
27 | "license": "Apache-2.0", | 27 | "license": "Apache-2.0", |
28 | "dependencies": { | 28 | "dependencies": { |
29 | "@paulcbetts/system-idle-time": "^1.0.4", | 29 | "@paulcbetts/system-idle-time": "^1.0.4", |
30 | "address-rfc2822": "^2.0.1", | ||
31 | "auto-launch": "https://github.com/meetfranz/node-auto-launch.git", | ||
30 | "babel-polyfill": "^6.23.0", | 32 | "babel-polyfill": "^6.23.0", |
31 | "babel-runtime": "^6.23.0", | 33 | "babel-runtime": "^6.23.0", |
32 | "classnames": "^2.2.5", | 34 | "classnames": "^2.2.5", |
33 | "electron-fetch": "^1.1.0", | 35 | "electron-fetch": "^1.1.0", |
34 | "electron-spellchecker": "^1.2.0", | 36 | "electron-spellchecker": "^1.2.0", |
35 | "electron-squirrel-startup": "^1.0.0", | ||
36 | "electron-updater": "^2.4.3", | 37 | "electron-updater": "^2.4.3", |
37 | "electron-window-state": "^4.1.0", | 38 | "electron-window-state": "^4.1.0", |
38 | "fs-extra": "^3.0.1", | 39 | "fs-extra": "^3.0.1", |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index 8b0b7563c..932b70cdc 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -499,7 +499,7 @@ export default class ServerApi { | |||
499 | 499 | ||
500 | return recipe; | 500 | return recipe; |
501 | }), | 501 | }), |
502 | ).catch(err => console.error(err)); | 502 | ).catch(err => console.error('Can\'t load recipe', err)); |
503 | } | 503 | } |
504 | 504 | ||
505 | _mapRecipePreviewModel(recipes) { | 505 | _mapRecipePreviewModel(recipes) { |
@@ -562,9 +562,16 @@ export default class ServerApi { | |||
562 | .filter(file => fs.statSync(path.join(recipesDirectory, file)).isDirectory() && file !== 'temp'); | 562 | .filter(file => fs.statSync(path.join(recipesDirectory, file)).isDirectory() && file !== 'temp'); |
563 | 563 | ||
564 | const recipes = paths.map((id) => { | 564 | const recipes = paths.map((id) => { |
565 | // eslint-disable-next-line | 565 | let Recipe; |
566 | const Recipe = require(id)(RecipeModel); | 566 | try { |
567 | return new Recipe(loadRecipeConfig(id)); | 567 | // eslint-disable-next-line |
568 | Recipe = require(id)(RecipeModel); | ||
569 | return new Recipe(loadRecipeConfig(id)); | ||
570 | } catch (err) { | ||
571 | console.error(err); | ||
572 | } | ||
573 | |||
574 | return false; | ||
568 | }).filter(recipe => recipe.id).map((data) => { | 575 | }).filter(recipe => recipe.id).map((data) => { |
569 | const recipe = data; | 576 | const recipe = data; |
570 | 577 | ||
@@ -579,7 +586,7 @@ export default class ServerApi { | |||
579 | 586 | ||
580 | return recipes; | 587 | return recipes; |
581 | } catch (err) { | 588 | } catch (err) { |
582 | console.debug('Folder `recipe/dev` does not exist'); | 589 | console.debug('Could not load dev recipes'); |
583 | return false; | 590 | return false; |
584 | } | 591 | } |
585 | } | 592 | } |
diff --git a/src/app.js b/src/app.js index b539ea494..a0b88611c 100644 --- a/src/app.js +++ b/src/app.js | |||
@@ -101,3 +101,7 @@ window.addEventListener('load', () => { | |||
101 | }; | 101 | }; |
102 | window.franz.render(); | 102 | window.franz.render(); |
103 | }); | 103 | }); |
104 | |||
105 | // Prevent drag and drop into window from redirecting | ||
106 | window.addEventListener('dragover', event => event.preventDefault()); | ||
107 | window.addEventListener('drop', event => event.preventDefault()); | ||
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index fac0f6b9a..9b359a78e 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -69,10 +69,6 @@ const messages = defineMessages({ | |||
69 | export default class EditServiceForm extends Component { | 69 | export default class EditServiceForm extends Component { |
70 | static propTypes = { | 70 | static propTypes = { |
71 | recipe: PropTypes.instanceOf(Recipe).isRequired, | 71 | recipe: PropTypes.instanceOf(Recipe).isRequired, |
72 | // service: PropTypes.oneOfType([ | ||
73 | // PropTypes.object, | ||
74 | // PropTypes.instanceOf(Service), | ||
75 | // ]), | ||
76 | service(props, propName) { | 72 | service(props, propName) { |
77 | if (props.action === 'edit' && !(props[propName] instanceof Service)) { | 73 | if (props.action === 'edit' && !(props[propName] instanceof Service)) { |
78 | return new Error(`'${propName}'' is expected to be of type 'Service' | 74 | return new Error(`'${propName}'' is expected to be of type 'Service' |
@@ -207,7 +203,7 @@ export default class EditServiceForm extends Component { | |||
207 | )} | 203 | )} |
208 | {recipe.hasCustomUrl && ( | 204 | {recipe.hasCustomUrl && ( |
209 | <TabItem title={intl.formatMessage(messages.tabOnPremise)}> | 205 | <TabItem title={intl.formatMessage(messages.tabOnPremise)}> |
210 | {user.isPremium ? ( | 206 | {user.isPremium || recipe.author.find(a => a.email === user.email) ? ( |
211 | <div> | 207 | <div> |
212 | <Input field={form.$('customUrl')} /> | 208 | <Input field={form.$('customUrl')} /> |
213 | {form.error === 'url-validation-error' && ( | 209 | {form.error === 'url-validation-error' && ( |
diff --git a/src/environment.js b/src/environment.js index 7bb2db134..e185120c0 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -8,16 +8,7 @@ export const isMac = process.platform === 'darwin'; | |||
8 | export const isWindows = process.platform === 'win32'; | 8 | export const isWindows = process.platform === 'win32'; |
9 | export const isLinux = process.platform === 'linux'; | 9 | export const isLinux = process.platform === 'linux'; |
10 | 10 | ||
11 | let ctrlShortcutKey; | 11 | export const ctrlKey = isMac ? '⌘' : 'Ctrl'; |
12 | if (isMac) { | ||
13 | ctrlShortcutKey = '⌘'; | ||
14 | } else if (isWindows) { | ||
15 | ctrlShortcutKey = 'Ctrl'; | ||
16 | } else { | ||
17 | ctrlShortcutKey = 'Alt'; | ||
18 | } | ||
19 | |||
20 | export const ctrlKey = ctrlShortcutKey; | ||
21 | 12 | ||
22 | let api; | 13 | let api; |
23 | if (!isDevMode || (isDevMode && useLiveAPI)) { | 14 | if (!isDevMode || (isDevMode && useLiveAPI)) { |
diff --git a/src/index.js b/src/index.js index 030736fee..f0fe56ae5 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -2,18 +2,14 @@ import { app, BrowserWindow, shell } from 'electron'; | |||
2 | import fs from 'fs-extra'; | 2 | import fs from 'fs-extra'; |
3 | import path from 'path'; | 3 | import path from 'path'; |
4 | 4 | ||
5 | /* eslint-disable */ | ||
6 | if (require('electron-squirrel-startup')) app.quit(); | ||
7 | |||
8 | import windowStateKeeper from 'electron-window-state'; | 5 | import windowStateKeeper from 'electron-window-state'; |
9 | 6 | ||
10 | import { isDevMode, isWindows } from './environment'; | 7 | import { isDevMode, isWindows } from './environment'; |
11 | import ipcApi from './electron/ipc-api'; | 8 | import ipcApi from './electron/ipc-api'; |
12 | import Tray from './lib/Tray'; | 9 | import Tray from './lib/Tray'; |
13 | import Settings from './electron/Settings'; | 10 | import Settings from './electron/Settings'; |
14 | import { appId } from './package.json'; | 11 | import { appId } from './package.json'; // eslint-disable-line import/no-unresolved |
15 | import './electron/exception'; | 12 | import './electron/exception'; |
16 | /* eslint-enable */ | ||
17 | 13 | ||
18 | // Keep a global reference of the window object, if you don't, the window will | 14 | // Keep a global reference of the window object, if you don't, the window will |
19 | // be closed automatically when the JavaScript object is garbage collected. | 15 | // be closed automatically when the JavaScript object is garbage collected. |
@@ -22,6 +18,7 @@ let willQuitApp = false; | |||
22 | 18 | ||
23 | // Ensure that the recipe directory exists | 19 | // Ensure that the recipe directory exists |
24 | fs.ensureDir(path.join(app.getPath('userData'), 'recipes')); | 20 | fs.ensureDir(path.join(app.getPath('userData'), 'recipes')); |
21 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); | ||
25 | 22 | ||
26 | // Set App ID for Windows | 23 | // Set App ID for Windows |
27 | if (isWindows) { | 24 | if (isWindows) { |
@@ -29,19 +26,18 @@ if (isWindows) { | |||
29 | } | 26 | } |
30 | 27 | ||
31 | // Force single window | 28 | // Force single window |
32 | if (process.platform !== 'darwin') { | 29 | const isSecondInstance = app.makeSingleInstance(() => { |
33 | const isSecondInstance = app.makeSingleInstance(() => { | 30 | if (mainWindow) { |
34 | if (mainWindow) { | 31 | if (mainWindow.isMinimized()) mainWindow.restore(); |
35 | if (mainWindow.isMinimized()) mainWindow.restore(); | 32 | mainWindow.focus(); |
36 | mainWindow.focus(); | ||
37 | } | ||
38 | }); | ||
39 | |||
40 | if (isSecondInstance) { | ||
41 | app.quit(); | ||
42 | } | 33 | } |
34 | }); | ||
35 | |||
36 | if (isSecondInstance) { | ||
37 | app.exit(); | ||
43 | } | 38 | } |
44 | 39 | ||
40 | |||
45 | // Initialize Settings | 41 | // Initialize Settings |
46 | const settings = new Settings(); | 42 | const settings = new Settings(); |
47 | 43 | ||
@@ -89,9 +85,13 @@ const createWindow = async () => { | |||
89 | // when you should delete the corresponding element. | 85 | // when you should delete the corresponding element. |
90 | if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) { | 86 | if (!willQuitApp && (settings.get('runInBackground') === undefined || settings.get('runInBackground'))) { |
91 | e.preventDefault(); | 87 | e.preventDefault(); |
92 | mainWindow.hide(); | 88 | if (isWindows) { |
89 | mainWindow.minimize(); | ||
90 | } else { | ||
91 | mainWindow.hide(); | ||
92 | } | ||
93 | 93 | ||
94 | if (process.platform === 'win32') { | 94 | if (isWindows && settings.get('minimizeToSystemTray')) { |
95 | mainWindow.setSkipTaskbar(true); | 95 | mainWindow.setSkipTaskbar(true); |
96 | } | 96 | } |
97 | } else { | 97 | } else { |
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 6bbf302ca..8f0a92c3d 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import { remote, shell } from 'electron'; | 1 | import { remote, shell } from 'electron'; |
2 | import { autorun, computed, observable, toJS } from 'mobx'; | 2 | import { autorun, computed, observable, toJS } from 'mobx'; |
3 | 3 | ||
4 | import { isMac, isLinux } from '../environment'; | 4 | import { isMac } from '../environment'; |
5 | 5 | ||
6 | const { app, Menu, dialog } = remote; | 6 | const { app, Menu, dialog } = remote; |
7 | 7 | ||
@@ -276,10 +276,9 @@ export default class FranzMenu { | |||
276 | const services = this.stores.services.enabled; | 276 | const services = this.stores.services.enabled; |
277 | 277 | ||
278 | if (this.stores.user.isLoggedIn) { | 278 | if (this.stores.user.isLoggedIn) { |
279 | const systemAcceleratorKey = isLinux ? 'Alt' : 'CmdOrCtrl'; | ||
280 | return services.map((service, i) => ({ | 279 | return services.map((service, i) => ({ |
281 | label: service.name, | 280 | label: service.name, |
282 | accelerator: i <= 9 ? `${systemAcceleratorKey}+${i + 1}` : null, | 281 | accelerator: i <= 9 ? `CmdOrCtrl+${i + 1}` : null, |
283 | type: 'radio', | 282 | type: 'radio', |
284 | checked: service.isActive, | 283 | checked: service.isActive, |
285 | click: () => { | 284 | click: () => { |
diff --git a/src/models/Recipe.js b/src/models/Recipe.js index 43a3450b1..9971df77c 100644 --- a/src/models/Recipe.js +++ b/src/models/Recipe.js | |||
@@ -1,7 +1,8 @@ | |||
1 | import emailParser from 'address-rfc2822'; | ||
2 | |||
1 | export default class Recipe { | 3 | export default class Recipe { |
2 | id = ''; | 4 | id = ''; |
3 | name = ''; | 5 | name = ''; |
4 | author = ''; | ||
5 | description = ''; | 6 | description = ''; |
6 | version = '1.0'; | 7 | version = '1.0'; |
7 | path = ''; | 8 | path = ''; |
@@ -25,12 +26,13 @@ export default class Recipe { | |||
25 | } | 26 | } |
26 | 27 | ||
27 | if (!data.id) { | 28 | if (!data.id) { |
28 | throw Error('Recipe requires Id'); | 29 | // Franz 4 recipes do not have an Id |
30 | throw Error(`Recipe '${data.name}' requires Id`); | ||
29 | } | 31 | } |
30 | 32 | ||
31 | this.id = data.id || this.id; | 33 | this.id = data.id || this.id; |
32 | this.name = data.name || this.name; | 34 | this.name = data.name || this.name; |
33 | this.author = data.author || this.author; | 35 | this.rawAuthor = data.author || this.author; |
34 | this.description = data.description || this.description; | 36 | this.description = data.description || this.description; |
35 | this.version = data.version || this.version; | 37 | this.version = data.version || this.version; |
36 | this.path = data.path; | 38 | this.path = data.path; |
@@ -49,4 +51,15 @@ export default class Recipe { | |||
49 | 51 | ||
50 | this.message = data.config.message || this.message; | 52 | this.message = data.config.message || this.message; |
51 | } | 53 | } |
54 | |||
55 | get author() { | ||
56 | try { | ||
57 | const addresses = emailParser.parse(this.rawAuthor); | ||
58 | return addresses.map(a => ({ email: a.address, name: a.phrase })); | ||
59 | } catch (err) { | ||
60 | console.warn(`Not a valid author for ${this.name}`); | ||
61 | } | ||
62 | |||
63 | return []; | ||
64 | } | ||
52 | } | 65 | } |
diff --git a/src/models/Service.js b/src/models/Service.js index 89d6748b5..c7276821a 100644 --- a/src/models/Service.js +++ b/src/models/Service.js | |||
@@ -58,7 +58,12 @@ export default class Service { | |||
58 | 58 | ||
59 | @computed get url() { | 59 | @computed get url() { |
60 | if (this.recipe.hasCustomUrl && this.customUrl) { | 60 | if (this.recipe.hasCustomUrl && this.customUrl) { |
61 | let url = normalizeUrl(this.customUrl); | 61 | let url; |
62 | try { | ||
63 | url = normalizeUrl(this.customUrl); | ||
64 | } catch (err) { | ||
65 | console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`); | ||
66 | } | ||
62 | 67 | ||
63 | if (typeof this.recipe.buildUrl === 'function') { | 68 | if (typeof this.recipe.buildUrl === 'function') { |
64 | url = this.recipe.buildUrl(url); | 69 | url = this.recipe.buildUrl(url); |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index f608a689e..ecfd621d3 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -2,19 +2,23 @@ import { remote, ipcRenderer, shell } from 'electron'; | |||
2 | import { action, observable } from 'mobx'; | 2 | import { action, observable } from 'mobx'; |
3 | import moment from 'moment'; | 3 | import moment from 'moment'; |
4 | import key from 'keymaster'; | 4 | import key from 'keymaster'; |
5 | import path from 'path'; | 5 | // import path from 'path'; |
6 | import idleTimer from '@paulcbetts/system-idle-time'; | 6 | import idleTimer from '@paulcbetts/system-idle-time'; |
7 | import AutoLaunch from 'auto-launch'; | ||
7 | 8 | ||
8 | import Store from './lib/Store'; | 9 | import Store from './lib/Store'; |
9 | import Request from './lib/Request'; | 10 | import Request from './lib/Request'; |
10 | import { CHECK_INTERVAL } from '../config'; | 11 | import { CHECK_INTERVAL } from '../config'; |
11 | import { isMac, isLinux } from '../environment'; | 12 | import { isMac } from '../environment'; |
12 | import locales from '../i18n/translations'; | 13 | import locales from '../i18n/translations'; |
13 | import { gaEvent } from '../lib/analytics'; | 14 | import { gaEvent } from '../lib/analytics'; |
14 | import Miner from '../lib/Miner'; | 15 | import Miner from '../lib/Miner'; |
15 | 16 | ||
16 | const { app, powerMonitor } = remote; | 17 | const { app, powerMonitor } = remote; |
17 | const defaultLocale = 'en-US'; | 18 | const defaultLocale = 'en-US'; |
19 | const autoLauncher = new AutoLaunch({ | ||
20 | name: 'Franz', | ||
21 | }); | ||
18 | 22 | ||
19 | export default class AppStore extends Store { | 23 | export default class AppStore extends Store { |
20 | updateStatusTypes = { | 24 | updateStatusTypes = { |
@@ -41,7 +45,7 @@ export default class AppStore extends Store { | |||
41 | miner = null; | 45 | miner = null; |
42 | @observable minerHashrate = 0.0; | 46 | @observable minerHashrate = 0.0; |
43 | 47 | ||
44 | constructor(...args: any) { | 48 | constructor(...args) { |
45 | super(...args); | 49 | super(...args); |
46 | 50 | ||
47 | // Register action handlers | 51 | // Register action handlers |
@@ -152,33 +156,24 @@ export default class AppStore extends Store { | |||
152 | indicator = '•'; | 156 | indicator = '•'; |
153 | } else if (unreadDirectMessageCount === 0 && unreadIndirectMessageCount === 0) { | 157 | } else if (unreadDirectMessageCount === 0 && unreadIndirectMessageCount === 0) { |
154 | indicator = 0; | 158 | indicator = 0; |
159 | } else { | ||
160 | indicator = parseInt(indicator, 10); | ||
155 | } | 161 | } |
156 | 162 | ||
157 | ipcRenderer.send('updateAppIndicator', { indicator }); | 163 | ipcRenderer.send('updateAppIndicator', { indicator }); |
158 | } | 164 | } |
159 | 165 | ||
160 | @action _launchOnStartup({ enable, openInBackground }) { | 166 | @action _launchOnStartup({ enable }) { |
161 | this.autoLaunchOnStart = enable; | 167 | this.autoLaunchOnStart = enable; |
162 | 168 | ||
163 | let settings = { | 169 | try { |
164 | openAtLogin: enable, | 170 | if (enable) { |
165 | }; | 171 | autoLauncher.enable(); |
166 | 172 | } else { | |
167 | // For Windows | 173 | autoLauncher.disable(); |
168 | if (process.platform === 'win32') { | ||
169 | settings = Object.assign({ | ||
170 | openAsHidden: openInBackground, | ||
171 | path: app.getPath('exe'), | ||
172 | args: [ | ||
173 | '--processStart', `"${path.basename(app.getPath('exe'))}"`, | ||
174 | ], | ||
175 | }, settings); | ||
176 | |||
177 | if (openInBackground) { | ||
178 | settings.args.push( | ||
179 | '--process-start-args', '"--hidden"', | ||
180 | ); | ||
181 | } | 174 | } |
175 | } catch (err) { | ||
176 | console.warn(err); | ||
182 | } | 177 | } |
183 | 178 | ||
184 | gaEvent('App', enable ? 'enable autostart' : 'disable autostart'); | 179 | gaEvent('App', enable ? 'enable autostart' : 'disable autostart'); |
@@ -287,31 +282,19 @@ export default class AppStore extends Store { | |||
287 | } | 282 | } |
288 | 283 | ||
289 | async _autoStart() { | 284 | async _autoStart() { |
290 | if (!isLinux) { | 285 | this.autoLaunchOnStart = await this._checkAutoStart(); |
291 | this._checkAutoStart(); | ||
292 | 286 | ||
293 | // we need to wait until the settings request is resolved | 287 | // we need to wait until the settings request is resolved |
294 | await this.stores.settings.allSettingsRequest; | 288 | await this.stores.settings.allSettingsRequest; |
295 | |||
296 | // We don't set autostart on first launch for macOS as disabling | ||
297 | // the option is currently broken | ||
298 | // https://github.com/meetfranz/franz/issues/17 | ||
299 | // https://github.com/electron/electron/issues/10880 | ||
300 | if (process.platform === 'darwin') return; | ||
301 | 289 | ||
302 | if (!this.stores.settings.all.appStarts) { | 290 | if (!this.stores.settings.all.appStarts) { |
303 | this.actions.app.launchOnStartup({ | 291 | this.actions.app.launchOnStartup({ |
304 | enable: true, | 292 | enable: true, |
305 | }); | 293 | }); |
306 | } | ||
307 | } | 294 | } |
308 | } | 295 | } |
309 | 296 | ||
310 | _checkAutoStart() { | 297 | async _checkAutoStart() { |
311 | const loginItem = app.getLoginItemSettings({ | 298 | return autoLauncher.isEnabled() || false; |
312 | path: app.getPath('exe'), | ||
313 | }); | ||
314 | |||
315 | this.autoLaunchOnStart = loginItem.openAtLogin; | ||
316 | } | 299 | } |
317 | } | 300 | } |
diff --git a/src/webview/notifications.js b/src/webview/notifications.js index b3397148d..4055b10de 100644 --- a/src/webview/notifications.js +++ b/src/webview/notifications.js | |||
@@ -1,47 +1,46 @@ | |||
1 | const { ipcRenderer } = require('electron'); | 1 | const { ipcRenderer } = require('electron'); |
2 | const uuidV1 = require('uuid/v1'); | 2 | const uuidV1 = require('uuid/v1'); |
3 | // const FranzNotificationStore = []; | ||
4 | 3 | ||
5 | class Notification { | 4 | class Notification { |
5 | static permission = 'granted'; | ||
6 | |||
6 | constructor(title = '', options = {}) { | 7 | constructor(title = '', options = {}) { |
7 | this.title = title; | 8 | this.title = title; |
8 | this.options = options; | 9 | this.options = options; |
9 | this.notificationId = uuidV1(); | 10 | this.notificationId = uuidV1(); |
10 | this.onclick = () => { }; | ||
11 | 11 | ||
12 | ipcRenderer.sendToHost('notification', Notification.onNotify({ | 12 | ipcRenderer.sendToHost('notification', this.onNotify({ |
13 | notificationId: this.notificationId, | 13 | notificationId: this.notificationId, |
14 | title, | 14 | title, |
15 | options, | 15 | options, |
16 | })); | 16 | })); |
17 | 17 | ||
18 | ipcRenderer.on(`notification-onclick:${this.notificationId}`, () => { | 18 | ipcRenderer.once(`notification-onclick:${this.notificationId}`, () => { |
19 | this.onclick(); | 19 | this.onclick(); |
20 | }); | 20 | }); |
21 | } | 21 | } |
22 | } | ||
23 | 22 | ||
24 | Notification.permission = 'granted'; | 23 | static requestPermission(cb = null) { |
24 | if (!cb) { | ||
25 | return new Promise((resolve) => { | ||
26 | resolve(Notification.permission); | ||
27 | }); | ||
28 | } | ||
25 | 29 | ||
26 | Notification.requestPermission = (cb = null) => { | 30 | if (typeof (cb) === 'function') { |
27 | console.log(this); | 31 | return cb(Notification.permission); |
28 | if (!cb) { | 32 | } |
29 | return new Promise((resolve) => { | ||
30 | resolve(Notification.permission); | ||
31 | }); | ||
32 | } | ||
33 | 33 | ||
34 | if (typeof (cb) === 'function') { | 34 | return Notification.permission; |
35 | return cb(Notification.permission); | ||
36 | } | 35 | } |
37 | 36 | ||
38 | return Notification.permission; | 37 | onNotify(data) { |
39 | }; | 38 | return data; |
39 | } | ||
40 | 40 | ||
41 | Notification.close = () => { | 41 | onClick() {} |
42 | // no implementation yet | ||
43 | }; | ||
44 | 42 | ||
45 | Notification.onNotify = data => data; | 43 | close() {} |
44 | } | ||
46 | 45 | ||
47 | window.Notification = Notification; | 46 | window.Notification = Notification; |
@@ -80,6 +80,12 @@ acorn@^5.1.1: | |||
80 | version "5.1.2" | 80 | version "5.1.2" |
81 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" | 81 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" |
82 | 82 | ||
83 | address-rfc2822@^2.0.1: | ||
84 | version "2.0.1" | ||
85 | resolved "https://registry.yarnpkg.com/address-rfc2822/-/address-rfc2822-2.0.1.tgz#1a1bdb942b5e20e2c1ba5d5f396d5824ff7ae6ea" | ||
86 | dependencies: | ||
87 | email-addresses "^3.0.0" | ||
88 | |||
83 | after@0.8.2: | 89 | after@0.8.2: |
84 | version "0.8.2" | 90 | version "0.8.2" |
85 | resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" | 91 | resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" |
@@ -151,6 +157,10 @@ anymatch@^1.3.0: | |||
151 | micromatch "^2.1.5" | 157 | micromatch "^2.1.5" |
152 | normalize-path "^2.0.0" | 158 | normalize-path "^2.0.0" |
153 | 159 | ||
160 | applescript@^1.0.0: | ||
161 | version "1.0.0" | ||
162 | resolved "https://registry.yarnpkg.com/applescript/-/applescript-1.0.0.tgz#bb87af568cad034a4e48c4bdaf6067a3a2701317" | ||
163 | |||
154 | aproba@^1.0.3: | 164 | aproba@^1.0.3: |
155 | version "1.1.2" | 165 | version "1.1.2" |
156 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" | 166 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" |
@@ -319,6 +329,16 @@ asynckit@^0.4.0: | |||
319 | version "0.4.0" | 329 | version "0.4.0" |
320 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" | 330 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" |
321 | 331 | ||
332 | "auto-launch@https://github.com/meetfranz/node-auto-launch.git": | ||
333 | version "5.0.1" | ||
334 | resolved "https://github.com/meetfranz/node-auto-launch.git#b90a0470467eb84435e6554ae9db1e2c6db79e61" | ||
335 | dependencies: | ||
336 | applescript "^1.0.0" | ||
337 | mkdirp "^0.5.1" | ||
338 | path-is-absolute "^1.0.0" | ||
339 | untildify "^3.0.2" | ||
340 | winreg "1.2.2" | ||
341 | |||
322 | aws-sign2@~0.6.0: | 342 | aws-sign2@~0.6.0: |
323 | version "0.6.0" | 343 | version "0.6.0" |
324 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" | 344 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" |
@@ -1998,12 +2018,6 @@ electron-spellchecker@^1.2.0: | |||
1998 | rxjs-serial-subscription "^0.1.1" | 2018 | rxjs-serial-subscription "^0.1.1" |
1999 | spawn-rx "^2.0.7" | 2019 | spawn-rx "^2.0.7" |
2000 | 2020 | ||
2001 | electron-squirrel-startup@^1.0.0: | ||
2002 | version "1.0.0" | ||
2003 | resolved "https://registry.yarnpkg.com/electron-squirrel-startup/-/electron-squirrel-startup-1.0.0.tgz#19b4e55933fa0ef8f556784b9c660f772546a0b8" | ||
2004 | dependencies: | ||
2005 | debug "^2.2.0" | ||
2006 | |||
2007 | electron-to-chromium@^1.3.18: | 2021 | electron-to-chromium@^1.3.18: |
2008 | version "1.3.20" | 2022 | version "1.3.20" |
2009 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz#2eedd5ccbae7ddc557f68ad1fce9c172e915e4e5" | 2023 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz#2eedd5ccbae7ddc557f68ad1fce9c172e915e4e5" |
@@ -2041,6 +2055,10 @@ electron@^1.7.9: | |||
2041 | electron-download "^3.0.1" | 2055 | electron-download "^3.0.1" |
2042 | extract-zip "^1.0.3" | 2056 | extract-zip "^1.0.3" |
2043 | 2057 | ||
2058 | email-addresses@^3.0.0: | ||
2059 | version "3.0.1" | ||
2060 | resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.0.1.tgz#c1fc20c189e7f96d4012d375db5feaccdd24391c" | ||
2061 | |||
2044 | emojis-list@^2.0.0: | 2062 | emojis-list@^2.0.0: |
2045 | version "2.1.0" | 2063 | version "2.1.0" |
2046 | resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" | 2064 | resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" |
@@ -5949,6 +5967,10 @@ universalify@^0.1.0: | |||
5949 | version "0.1.1" | 5967 | version "0.1.1" |
5950 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" | 5968 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" |
5951 | 5969 | ||
5970 | untildify@^3.0.2: | ||
5971 | version "3.0.2" | ||
5972 | resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" | ||
5973 | |||
5952 | unzip-response@^2.0.1: | 5974 | unzip-response@^2.0.1: |
5953 | version "2.0.1" | 5975 | version "2.0.1" |
5954 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" | 5976 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" |
@@ -6133,6 +6155,10 @@ window-size@^0.1.4: | |||
6133 | version "0.1.4" | 6155 | version "0.1.4" |
6134 | resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" | 6156 | resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" |
6135 | 6157 | ||
6158 | winreg@1.2.2: | ||
6159 | version "1.2.2" | ||
6160 | resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.2.tgz#8509afa3b71c5bbd110a6d7c6247ec67736c598f" | ||
6161 | |||
6136 | word-wrap@^1.0.3: | 6162 | word-wrap@^1.0.3: |
6137 | version "1.2.3" | 6163 | version "1.2.3" |
6138 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" | 6164 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" |