diff options
Diffstat (limited to 'src/stores')
-rw-r--r-- | src/stores/AppStore.js | 53 | ||||
-rw-r--r-- | src/stores/DictionaryStore.js | 45 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 50 | ||||
-rw-r--r-- | src/stores/RecipesStore.js | 2 | ||||
-rw-r--r-- | src/stores/RequestStore.js | 2 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 41 | ||||
-rw-r--r-- | src/stores/SettingsStore.js | 116 | ||||
-rw-r--r-- | src/stores/UIStore.js | 12 | ||||
-rw-r--r-- | src/stores/UserStore.js | 10 | ||||
-rw-r--r-- | src/stores/index.js | 4 |
10 files changed, 276 insertions, 59 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 38edff1b4..6f156a96d 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -12,12 +12,14 @@ import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; | |||
12 | import { isMac, isLinux, isWindows } from '../environment'; | 12 | import { isMac, isLinux, isWindows } from '../environment'; |
13 | import locales from '../i18n/translations'; | 13 | import locales from '../i18n/translations'; |
14 | import { gaEvent } from '../lib/analytics'; | 14 | import { gaEvent } from '../lib/analytics'; |
15 | import { onVisibilityChange } from '../helpers/visibility-helper'; | ||
16 | import { getLocale } from '../helpers/i18n-helpers'; | ||
15 | 17 | ||
16 | import { getServiceIdsFromPartitions, removeServicePartitionDirectory } from '../helpers/service-helpers.js'; | 18 | import { getServiceIdsFromPartitions, removeServicePartitionDirectory } from '../helpers/service-helpers.js'; |
17 | 19 | ||
18 | const debug = require('debug')('AppStore'); | 20 | const debug = require('debug')('Franz:AppStore'); |
19 | 21 | ||
20 | const { app } = remote; | 22 | const { app, systemPreferences } = remote; |
21 | 23 | ||
22 | const mainWindow = remote.getCurrentWindow(); | 24 | const mainWindow = remote.getCurrentWindow(); |
23 | 25 | ||
@@ -50,10 +52,16 @@ export default class AppStore extends Store { | |||
50 | 52 | ||
51 | @observable isSystemMuteOverridden = false; | 53 | @observable isSystemMuteOverridden = false; |
52 | 54 | ||
55 | @observable isSystemDarkModeEnabled = false; | ||
56 | |||
53 | @observable isClearingAllCache = false; | 57 | @observable isClearingAllCache = false; |
54 | 58 | ||
55 | @observable isFullScreen = mainWindow.isFullScreen(); | 59 | @observable isFullScreen = mainWindow.isFullScreen(); |
56 | 60 | ||
61 | @observable isFocused = true; | ||
62 | |||
63 | dictionaries = []; | ||
64 | |||
57 | constructor(...args) { | 65 | constructor(...args) { |
58 | super(...args); | 66 | super(...args); |
59 | 67 | ||
@@ -77,7 +85,7 @@ export default class AppStore extends Store { | |||
77 | ]); | 85 | ]); |
78 | } | 86 | } |
79 | 87 | ||
80 | setup() { | 88 | async setup() { |
81 | this._appStartsCounter(); | 89 | this._appStartsCounter(); |
82 | // Focus the active service | 90 | // Focus the active service |
83 | window.addEventListener('focus', this.actions.service.focusActiveService); | 91 | window.addEventListener('focus', this.actions.service.focusActiveService); |
@@ -159,6 +167,14 @@ export default class AppStore extends Store { | |||
159 | this.locale = this._getDefaultLocale(); | 167 | this.locale = this._getDefaultLocale(); |
160 | 168 | ||
161 | this._healthCheck(); | 169 | this._healthCheck(); |
170 | |||
171 | this.isSystemDarkModeEnabled = systemPreferences.isDarkMode(); | ||
172 | |||
173 | onVisibilityChange((isVisible) => { | ||
174 | this.isFocused = isVisible; | ||
175 | |||
176 | debug('Window is visible/focused', isVisible); | ||
177 | }); | ||
162 | } | 178 | } |
163 | 179 | ||
164 | @computed get cacheSize() { | 180 | @computed get cacheSize() { |
@@ -304,31 +320,12 @@ export default class AppStore extends Store { | |||
304 | } | 320 | } |
305 | 321 | ||
306 | _getDefaultLocale() { | 322 | _getDefaultLocale() { |
307 | let locale = app.getLocale(); | 323 | return getLocale({ |
308 | if (locales[locale] === undefined) { | 324 | locale: app.getLocale(), |
309 | let localeFuzzy; | 325 | locales, |
310 | Object.keys(locales).forEach((localStr) => { | 326 | defaultLocale, |
311 | if (locales && Object.hasOwnProperty.call(locales, localStr)) { | 327 | fallbackLocale: DEFAULT_APP_SETTINGS.fallbackLocale, |
312 | if (locale.substring(0, 2) === localStr.substring(0, 2)) { | 328 | }); |
313 | localeFuzzy = localStr; | ||
314 | } | ||
315 | } | ||
316 | }); | ||
317 | |||
318 | if (localeFuzzy !== undefined) { | ||
319 | locale = localeFuzzy; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | if (locales[locale] === undefined) { | ||
324 | locale = defaultLocale; | ||
325 | } | ||
326 | |||
327 | if (!locale) { | ||
328 | locale = DEFAULT_APP_SETTINGS.fallbackLocale; | ||
329 | } | ||
330 | |||
331 | return locale; | ||
332 | } | 329 | } |
333 | 330 | ||
334 | _muteAppHandler() { | 331 | _muteAppHandler() { |
diff --git a/src/stores/DictionaryStore.js b/src/stores/DictionaryStore.js new file mode 100644 index 000000000..b9c5f2abf --- /dev/null +++ b/src/stores/DictionaryStore.js | |||
@@ -0,0 +1,45 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import { createDownloader } from 'hunspell-dict-downloader'; | ||
3 | |||
4 | import Store from './lib/Store'; | ||
5 | |||
6 | import { DICTIONARY_PATH } from '../config'; | ||
7 | |||
8 | const debug = require('debug')('Franz:DictionaryStore'); | ||
9 | |||
10 | export default class DictionaryStore extends Store { | ||
11 | @observable available = [] | ||
12 | @observable installed = [] | ||
13 | |||
14 | _dictDownloader = null | ||
15 | |||
16 | constructor(...args) { | ||
17 | super(...args); | ||
18 | |||
19 | this.registerReactions([ | ||
20 | this._downloadDictForUserLocale.bind(this), | ||
21 | ]); | ||
22 | } | ||
23 | |||
24 | async setup() { | ||
25 | this._dictDownloader = await createDownloader(DICTIONARY_PATH); | ||
26 | debug('dicts', this._dictDownloader); | ||
27 | |||
28 | this.available = this._dictDownloader.availableDictionaries; | ||
29 | this.installed = this._dictDownloader.installedDictionaries; | ||
30 | |||
31 | if (!this.installed.includes('en-us')) { | ||
32 | this._dictDownloader.installDictionary('en-us'); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | _downloadDictForUserLocale() { | ||
37 | const spellcheckerLanguage = this.stores.settings.app.spellcheckerLanguage; | ||
38 | |||
39 | debug('trying to Downloading dict for', spellcheckerLanguage); | ||
40 | if (!this.installed.includes(spellcheckerLanguage) && this.available.includes(spellcheckerLanguage) && spellcheckerLanguage !== 'en-us') { | ||
41 | debug('Downloading dict for', spellcheckerLanguage); | ||
42 | this._dictDownloader.installDictionary(spellcheckerLanguage); | ||
43 | } | ||
44 | } | ||
45 | } | ||
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js new file mode 100644 index 000000000..10c893d3f --- /dev/null +++ b/src/stores/FeaturesStore.js | |||
@@ -0,0 +1,50 @@ | |||
1 | import { computed, observable } from 'mobx'; | ||
2 | |||
3 | import Store from './lib/Store'; | ||
4 | import CachedRequest from './lib/CachedRequest'; | ||
5 | |||
6 | import delayApp from '../features/delayApp'; | ||
7 | import spellchecker from '../features/spellchecker'; | ||
8 | import serviceProxy from '../features/serviceProxy'; | ||
9 | |||
10 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | ||
11 | |||
12 | export default class FeaturesStore extends Store { | ||
13 | @observable defaultFeaturesRequest = new CachedRequest(this.api.features, 'default'); | ||
14 | @observable featuresRequest = new CachedRequest(this.api.features, 'features'); | ||
15 | |||
16 | async setup() { | ||
17 | this.registerReactions([ | ||
18 | this._monitorLoginStatus.bind(this), | ||
19 | ]); | ||
20 | |||
21 | await this.featuresRequest._promise; | ||
22 | setTimeout(this._enableFeatures.bind(this), 1); | ||
23 | } | ||
24 | |||
25 | @computed get anonymousFeatures() { | ||
26 | return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; | ||
27 | } | ||
28 | |||
29 | @computed get features() { | ||
30 | if (this.stores.user.isLoggedIn) { | ||
31 | return this.featuresRequest.execute().result || DEFAULT_FEATURES_CONFIG; | ||
32 | } | ||
33 | |||
34 | return DEFAULT_FEATURES_CONFIG; | ||
35 | } | ||
36 | |||
37 | _monitorLoginStatus() { | ||
38 | if (this.stores.user.isLoggedIn) { | ||
39 | this.featuresRequest.invalidate({ immediately: true }); | ||
40 | } else { | ||
41 | this.defaultFeaturesRequest.invalidate({ immediately: true }); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | _enableFeatures() { | ||
46 | delayApp(this.stores, this.actions); | ||
47 | spellchecker(this.stores, this.actions); | ||
48 | serviceProxy(this.stores, this.actions); | ||
49 | } | ||
50 | } | ||
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js index a24308f6a..f2480bc8e 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.js | |||
@@ -5,7 +5,7 @@ import CachedRequest from './lib/CachedRequest'; | |||
5 | import Request from './lib/Request'; | 5 | import Request from './lib/Request'; |
6 | import { matchRoute } from '../helpers/routing-helpers'; | 6 | import { matchRoute } from '../helpers/routing-helpers'; |
7 | 7 | ||
8 | const debug = require('debug')('RecipeStore'); | 8 | const debug = require('debug')('Franz:RecipeStore'); |
9 | 9 | ||
10 | export default class RecipesStore extends Store { | 10 | export default class RecipesStore extends Store { |
11 | @observable allRecipesRequest = new CachedRequest(this.api.recipes, 'all'); | 11 | @observable allRecipesRequest = new CachedRequest(this.api.recipes, 'all'); |
diff --git a/src/stores/RequestStore.js b/src/stores/RequestStore.js index 595852583..bbfe6f6df 100644 --- a/src/stores/RequestStore.js +++ b/src/stores/RequestStore.js | |||
@@ -2,7 +2,7 @@ import { action, computed, observable } from 'mobx'; | |||
2 | 2 | ||
3 | import Store from './lib/Store'; | 3 | import Store from './lib/Store'; |
4 | 4 | ||
5 | const debug = require('debug')('RequestsStore'); | 5 | const debug = require('debug')('Franz:RequestsStore'); |
6 | 6 | ||
7 | export default class RequestStore extends Store { | 7 | export default class RequestStore extends Store { |
8 | @observable userInfoRequest; | 8 | @observable userInfoRequest; |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index ccb85421a..99b091589 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -7,7 +7,7 @@ import CachedRequest from './lib/CachedRequest'; | |||
7 | import { matchRoute } from '../helpers/routing-helpers'; | 7 | import { matchRoute } from '../helpers/routing-helpers'; |
8 | import { gaEvent } from '../lib/analytics'; | 8 | import { gaEvent } from '../lib/analytics'; |
9 | 9 | ||
10 | const debug = require('debug')('ServiceStore'); | 10 | const debug = require('debug')('Franz:ServiceStore'); |
11 | 11 | ||
12 | export default class ServicesStore extends Store { | 12 | export default class ServicesStore extends Store { |
13 | @observable allServicesRequest = new CachedRequest(this.api.services, 'all'); | 13 | @observable allServicesRequest = new CachedRequest(this.api.services, 'all'); |
@@ -67,9 +67,14 @@ export default class ServicesStore extends Store { | |||
67 | } | 67 | } |
68 | 68 | ||
69 | setup() { | 69 | setup() { |
70 | // Single key reactions | 70 | // Single key reactions for the sake of your CPU |
71 | reaction( | 71 | reaction( |
72 | () => this.stores.settings.all.app.enableSpellchecking, | 72 | () => this.stores.settings.app.enableSpellchecking, |
73 | () => this._shareSettingsWithServiceProcess(), | ||
74 | ); | ||
75 | |||
76 | reaction( | ||
77 | () => this.stores.settings.app.spellcheckerLanguage, | ||
73 | () => this._shareSettingsWithServiceProcess(), | 78 | () => this._shareSettingsWithServiceProcess(), |
74 | ); | 79 | ); |
75 | } | 80 | } |
@@ -93,7 +98,7 @@ export default class ServicesStore extends Store { | |||
93 | return this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; | 98 | return this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; |
94 | } | 99 | } |
95 | 100 | ||
96 | // This is just used to avoid unnecessary rerendering of resource-heavy webviews | 101 | // This is just used to avoid unnecessary rerendering of resource-heavy webviews |
97 | @computed get allDisplayedUnordered() { | 102 | @computed get allDisplayedUnordered() { |
98 | const services = this.allServicesRequest.execute().result || []; | 103 | const services = this.allServicesRequest.execute().result || []; |
99 | return this.stores.settings.all.app.showDisabledServices ? services : services.filter(service => service.isEnabled); | 104 | return this.stores.settings.all.app.showDisabledServices ? services : services.filter(service => service.isEnabled); |
@@ -143,6 +148,7 @@ export default class ServicesStore extends Store { | |||
143 | // Actions | 148 | // Actions |
144 | @action async _createService({ recipeId, serviceData, redirect = true }) { | 149 | @action async _createService({ recipeId, serviceData, redirect = true }) { |
145 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | 150 | const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); |
151 | |||
146 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; | 152 | const response = await this.createServiceRequest.execute(recipeId, data)._promise; |
147 | 153 | ||
148 | this.allServicesRequest.patch((result) => { | 154 | this.allServicesRequest.patch((result) => { |
@@ -150,6 +156,13 @@ export default class ServicesStore extends Store { | |||
150 | result.push(response.data); | 156 | result.push(response.data); |
151 | }); | 157 | }); |
152 | 158 | ||
159 | this.actions.settings.update({ | ||
160 | type: 'proxy', | ||
161 | data: { | ||
162 | [`${response.data.id}`]: data.proxy, | ||
163 | }, | ||
164 | }); | ||
165 | |||
153 | this.actionStatus = response.status || []; | 166 | this.actionStatus = response.status || []; |
154 | 167 | ||
155 | if (redirect) { | 168 | if (redirect) { |
@@ -214,6 +227,21 @@ export default class ServicesStore extends Store { | |||
214 | await request._promise; | 227 | await request._promise; |
215 | this.actionStatus = request.result.status; | 228 | this.actionStatus = request.result.status; |
216 | 229 | ||
230 | if (service.isEnabled) { | ||
231 | this._sendIPCMessage({ | ||
232 | serviceId, | ||
233 | channel: 'service-settings-update', | ||
234 | args: newData, | ||
235 | }); | ||
236 | } | ||
237 | |||
238 | this.actions.settings.update({ | ||
239 | type: 'proxy', | ||
240 | data: { | ||
241 | [`${serviceId}`]: data.proxy, | ||
242 | }, | ||
243 | }); | ||
244 | |||
217 | if (redirect) { | 245 | if (redirect) { |
218 | this.stores.router.push('/settings/services'); | 246 | this.stores.router.push('/settings/services'); |
219 | gaEvent('Service', 'update', service.recipe.id); | 247 | gaEvent('Service', 'update', service.recipe.id); |
@@ -411,6 +439,8 @@ export default class ServicesStore extends Store { | |||
411 | 439 | ||
412 | @action _reload({ serviceId }) { | 440 | @action _reload({ serviceId }) { |
413 | const service = this.one(serviceId); | 441 | const service = this.one(serviceId); |
442 | if (!service.isEnabled) return; | ||
443 | |||
414 | service.resetMessageCount(); | 444 | service.resetMessageCount(); |
415 | 445 | ||
416 | service.webview.loadURL(service.url); | 446 | service.webview.loadURL(service.url); |
@@ -567,9 +597,10 @@ export default class ServicesStore extends Store { | |||
567 | } | 597 | } |
568 | 598 | ||
569 | _shareSettingsWithServiceProcess() { | 599 | _shareSettingsWithServiceProcess() { |
600 | const settings = this.stores.settings.app; | ||
570 | this.actions.service.sendIPCMessageToAllServices({ | 601 | this.actions.service.sendIPCMessageToAllServices({ |
571 | channel: 'settings-update', | 602 | channel: 'settings-update', |
572 | args: this.stores.settings.all.app, | 603 | args: settings, |
573 | }); | 604 | }); |
574 | } | 605 | } |
575 | 606 | ||
diff --git a/src/stores/SettingsStore.js b/src/stores/SettingsStore.js index d8519c609..9ea14a911 100644 --- a/src/stores/SettingsStore.js +++ b/src/stores/SettingsStore.js | |||
@@ -1,54 +1,105 @@ | |||
1 | import { remote, ipcRenderer } from 'electron'; | ||
1 | import { action, computed, observable } from 'mobx'; | 2 | import { action, computed, observable } from 'mobx'; |
2 | import localStorage from 'mobx-localstorage'; | 3 | import localStorage from 'mobx-localstorage'; |
3 | 4 | ||
4 | import Store from './lib/Store'; | 5 | import Store from './lib/Store'; |
5 | import SettingsModel from '../models/Settings'; | ||
6 | import Request from './lib/Request'; | 6 | import Request from './lib/Request'; |
7 | import CachedRequest from './lib/CachedRequest'; | 7 | import CachedRequest from './lib/CachedRequest'; |
8 | import { getLocale } from '../helpers/i18n-helpers'; | ||
8 | 9 | ||
9 | const debug = require('debug')('SettingsStore'); | 10 | import { DEFAULT_APP_SETTINGS, FILE_SYSTEM_SETTINGS_TYPES } from '../config'; |
11 | import { SPELLCHECKER_LOCALES } from '../i18n/languages'; | ||
12 | |||
13 | const { systemPreferences } = remote; | ||
14 | const debug = require('debug')('Franz:SettingsStore'); | ||
10 | 15 | ||
11 | export default class SettingsStore extends Store { | 16 | export default class SettingsStore extends Store { |
12 | @observable appSettingsRequest = new CachedRequest(this.api.local, 'getAppSettings'); | 17 | @observable appSettingsRequest = new CachedRequest(this.api.local, 'getAppSettings'); |
13 | @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings'); | 18 | @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings'); |
14 | 19 | ||
20 | @observable fileSystemSettingsRequests = []; | ||
21 | |||
22 | fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES; | ||
23 | @observable _fileSystemSettingsCache = { | ||
24 | app: DEFAULT_APP_SETTINGS, | ||
25 | proxy: {}, | ||
26 | }; | ||
27 | |||
15 | constructor(...args) { | 28 | constructor(...args) { |
16 | super(...args); | 29 | super(...args); |
17 | 30 | ||
18 | // Register action handlers | 31 | // Register action handlers |
19 | this.actions.settings.update.listen(this._update.bind(this)); | 32 | this.actions.settings.update.listen(this._update.bind(this)); |
20 | this.actions.settings.remove.listen(this._remove.bind(this)); | 33 | this.actions.settings.remove.listen(this._remove.bind(this)); |
34 | |||
35 | this.fileSystemSettingsTypes.forEach((type) => { | ||
36 | this.fileSystemSettingsRequests[type] = new CachedRequest(this.api.local, 'getAppSettings'); | ||
37 | }); | ||
38 | |||
39 | ipcRenderer.on('appSettings', (event, resp) => { | ||
40 | debug('Get appSettings resolves', resp, resp.type, resp.data); | ||
41 | |||
42 | this._fileSystemSettingsCache[resp.type] = resp.data; | ||
43 | }); | ||
44 | |||
45 | this.fileSystemSettingsTypes.forEach((type) => { | ||
46 | ipcRenderer.send('getAppSettings', type); | ||
47 | }); | ||
21 | } | 48 | } |
22 | 49 | ||
23 | async setup() { | 50 | async setup() { |
24 | // We need to wait until `appSettingsRequest` has been executed once, otherwise we can't patch the result. If we don't wait we'd run into an issue with mobx not reacting to changes of previously not existing keys | 51 | // We need to wait until `appSettingsRequest` has been executed once, otherwise we can't patch the result. If we don't wait we'd run into an issue with mobx not reacting to changes of previously not existing keys |
25 | await this.appSettingsRequest._promise; | 52 | await this.appSettingsRequest._promise; |
26 | this._migrate(); | 53 | await this._migrate(); |
54 | } | ||
55 | |||
56 | @computed get app() { | ||
57 | return this._fileSystemSettingsCache.app || DEFAULT_APP_SETTINGS; | ||
58 | } | ||
59 | |||
60 | @computed get proxy() { | ||
61 | return this._fileSystemSettingsCache.proxy || {}; | ||
62 | } | ||
63 | |||
64 | @computed get service() { | ||
65 | return localStorage.getItem('service') || { | ||
66 | activeService: '', | ||
67 | }; | ||
68 | } | ||
69 | |||
70 | @computed get stats() { | ||
71 | return localStorage.getItem('stats') || { | ||
72 | activeService: '', | ||
73 | }; | ||
74 | } | ||
75 | |||
76 | @computed get migration() { | ||
77 | return localStorage.getItem('migration') || {}; | ||
27 | } | 78 | } |
28 | 79 | ||
29 | @computed get all() { | 80 | @computed get all() { |
30 | return new SettingsModel({ | 81 | return { |
31 | app: this.appSettingsRequest.execute().result || {}, | 82 | app: this.app, |
32 | service: localStorage.getItem('service') || {}, | 83 | proxy: this.proxy, |
33 | group: localStorage.getItem('group') || {}, | 84 | service: this.service, |
34 | stats: localStorage.getItem('stats') || {}, | 85 | stats: this.stats, |
35 | migration: localStorage.getItem('migration') || {}, | 86 | migration: this.migration, |
36 | }); | 87 | }; |
37 | } | 88 | } |
38 | 89 | ||
39 | @action async _update({ type, data }) { | 90 | @action async _update({ type, data }) { |
40 | const appSettings = this.all; | 91 | const appSettings = this.all; |
41 | if (type !== 'app') { | 92 | if (!this.fileSystemSettingsTypes.includes(type)) { |
42 | debug('Update settings', type, data, this.all); | 93 | debug('Update settings', type, data, this.all); |
43 | localStorage.setItem(type, Object.assign(appSettings[type], data)); | 94 | localStorage.setItem(type, Object.assign(appSettings[type], data)); |
44 | } else { | 95 | } else { |
45 | debug('Update settings on file system', type, data); | 96 | debug('Update settings on file system', type, data); |
46 | this.updateAppSettingsRequest.execute(data); | 97 | ipcRenderer.send('updateAppSettings', { |
47 | 98 | type, | |
48 | this.appSettingsRequest.patch((result) => { | 99 | data, |
49 | if (!result) return; | ||
50 | Object.assign(result, data); | ||
51 | }); | 100 | }); |
101 | |||
102 | Object.assign(this._fileSystemSettingsCache[type], data); | ||
52 | } | 103 | } |
53 | } | 104 | } |
54 | 105 | ||
@@ -67,8 +118,8 @@ export default class SettingsStore extends Store { | |||
67 | } | 118 | } |
68 | 119 | ||
69 | // Helper | 120 | // Helper |
70 | _migrate() { | 121 | async _migrate() { |
71 | const legacySettings = localStorage.getItem('app'); | 122 | const legacySettings = localStorage.getItem('app') || {}; |
72 | 123 | ||
73 | if (!this.all.migration['5.0.0-beta.17-settings']) { | 124 | if (!this.all.migration['5.0.0-beta.17-settings']) { |
74 | this.actions.settings.update({ | 125 | this.actions.settings.update({ |
@@ -104,5 +155,34 @@ export default class SettingsStore extends Store { | |||
104 | 155 | ||
105 | debug('Migrated settings to split stores'); | 156 | debug('Migrated settings to split stores'); |
106 | } | 157 | } |
158 | |||
159 | // Enable dark mode once | ||
160 | if (!this.all.migration['5.0.0-beta.19-settings']) { | ||
161 | const spellcheckerLanguage = getLocale({ | ||
162 | locale: this.stores.settings.app.locale, | ||
163 | locales: SPELLCHECKER_LOCALES, | ||
164 | defaultLocale: DEFAULT_APP_SETTINGS.spellcheckerLanguage, | ||
165 | fallbackLocale: DEFAULT_APP_SETTINGS.spellcheckerLanguage, | ||
166 | }); | ||
167 | |||
168 | this.actions.settings.update({ | ||
169 | type: 'app', | ||
170 | data: { | ||
171 | darkMode: systemPreferences.isDarkMode(), | ||
172 | spellcheckerLanguage, | ||
173 | }, | ||
174 | }); | ||
175 | |||
176 | this.actions.settings.update({ | ||
177 | type: 'migration', | ||
178 | data: { | ||
179 | '5.0.0-beta.19-settings': true, | ||
180 | }, | ||
181 | }); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | _getFileBasedSettings(type) { | ||
186 | ipcRenderer.send('getAppSettings', type); | ||
107 | } | 187 | } |
108 | } | 188 | } |
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index b391bdcae..d37ebe4c7 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js | |||
@@ -1,6 +1,8 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { action, observable, computed } from 'mobx'; |
2 | 2 | ||
3 | import Store from './lib/Store'; | 3 | import Store from './lib/Store'; |
4 | import * as themeDefault from '../theme/default'; | ||
5 | import * as themeDark from '../theme/dark'; | ||
4 | 6 | ||
5 | export default class UIStore extends Store { | 7 | export default class UIStore extends Store { |
6 | @observable showServicesUpdatedInfoBar = false; | 8 | @observable showServicesUpdatedInfoBar = false; |
@@ -20,13 +22,21 @@ export default class UIStore extends Store { | |||
20 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; | 22 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; |
21 | } | 23 | } |
22 | 24 | ||
25 | @computed get theme() { | ||
26 | if (this.stores.settings.all.app.darkMode) { | ||
27 | return Object.assign({}, themeDefault, themeDark); | ||
28 | } | ||
29 | |||
30 | return themeDefault; | ||
31 | } | ||
32 | |||
23 | // Actions | 33 | // Actions |
24 | @action _openSettings({ path = '/settings' }) { | 34 | @action _openSettings({ path = '/settings' }) { |
25 | const settingsPath = path !== '/settings' ? `/settings/${path}` : path; | 35 | const settingsPath = path !== '/settings' ? `/settings/${path}` : path; |
26 | this.stores.router.push(settingsPath); | 36 | this.stores.router.push(settingsPath); |
27 | } | 37 | } |
28 | 38 | ||
29 | @action _closeSettings(): void { | 39 | @action _closeSettings() { |
30 | this.stores.router.push('/'); | 40 | this.stores.router.push('/'); |
31 | } | 41 | } |
32 | 42 | ||
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 574616925..26ac2c60e 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -9,7 +9,7 @@ import Request from './lib/Request'; | |||
9 | import CachedRequest from './lib/CachedRequest'; | 9 | import CachedRequest from './lib/CachedRequest'; |
10 | import { gaEvent } from '../lib/analytics'; | 10 | import { gaEvent } from '../lib/analytics'; |
11 | 11 | ||
12 | const debug = require('debug')('UserStore'); | 12 | const debug = require('debug')('Franz:UserStore'); |
13 | 13 | ||
14 | // TODO: split stores into UserStore and AuthStore | 14 | // TODO: split stores into UserStore and AuthStore |
15 | export default class UserStore extends Store { | 15 | export default class UserStore extends Store { |
@@ -122,13 +122,13 @@ export default class UserStore extends Store { | |||
122 | } | 122 | } |
123 | 123 | ||
124 | @computed get data() { | 124 | @computed get data() { |
125 | this.getUserInfoRequest.execute(); | 125 | if (!this.isLoggedIn) return {}; |
126 | return this.getUserInfoRequest.result || {}; | 126 | |
127 | return this.getUserInfoRequest.execute().result || {}; | ||
127 | } | 128 | } |
128 | 129 | ||
129 | @computed get legacyServices() { | 130 | @computed get legacyServices() { |
130 | this.getLegacyServicesRequest.execute(); | 131 | return this.getLegacyServicesRequest.execute() || {}; |
131 | return this.getLegacyServicesRequest.result || []; | ||
132 | } | 132 | } |
133 | 133 | ||
134 | // Actions | 134 | // Actions |
diff --git a/src/stores/index.js b/src/stores/index.js index 2d99e3952..f547d0a7a 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -1,5 +1,6 @@ | |||
1 | import AppStore from './AppStore'; | 1 | import AppStore from './AppStore'; |
2 | import UserStore from './UserStore'; | 2 | import UserStore from './UserStore'; |
3 | import FeaturesStore from './FeaturesStore'; | ||
3 | import SettingsStore from './SettingsStore'; | 4 | import SettingsStore from './SettingsStore'; |
4 | import ServicesStore from './ServicesStore'; | 5 | import ServicesStore from './ServicesStore'; |
5 | import RecipesStore from './RecipesStore'; | 6 | import RecipesStore from './RecipesStore'; |
@@ -8,6 +9,7 @@ import UIStore from './UIStore'; | |||
8 | import PaymentStore from './PaymentStore'; | 9 | import PaymentStore from './PaymentStore'; |
9 | import NewsStore from './NewsStore'; | 10 | import NewsStore from './NewsStore'; |
10 | import RequestStore from './RequestStore'; | 11 | import RequestStore from './RequestStore'; |
12 | import DictionaryStore from './DictionaryStore'; | ||
11 | import GlobalErrorStore from './GlobalErrorStore'; | 13 | import GlobalErrorStore from './GlobalErrorStore'; |
12 | 14 | ||
13 | export default (api, actions, router) => { | 15 | export default (api, actions, router) => { |
@@ -16,6 +18,7 @@ export default (api, actions, router) => { | |||
16 | router, | 18 | router, |
17 | app: new AppStore(stores, api, actions), | 19 | app: new AppStore(stores, api, actions), |
18 | user: new UserStore(stores, api, actions), | 20 | user: new UserStore(stores, api, actions), |
21 | features: new FeaturesStore(stores, api, actions), | ||
19 | settings: new SettingsStore(stores, api, actions), | 22 | settings: new SettingsStore(stores, api, actions), |
20 | services: new ServicesStore(stores, api, actions), | 23 | services: new ServicesStore(stores, api, actions), |
21 | recipes: new RecipesStore(stores, api, actions), | 24 | recipes: new RecipesStore(stores, api, actions), |
@@ -24,6 +27,7 @@ export default (api, actions, router) => { | |||
24 | payment: new PaymentStore(stores, api, actions), | 27 | payment: new PaymentStore(stores, api, actions), |
25 | news: new NewsStore(stores, api, actions), | 28 | news: new NewsStore(stores, api, actions), |
26 | requests: new RequestStore(stores, api, actions), | 29 | requests: new RequestStore(stores, api, actions), |
30 | dictionary: new DictionaryStore(stores, api, actions), | ||
27 | globalError: new GlobalErrorStore(stores, api, actions), | 31 | globalError: new GlobalErrorStore(stores, api, actions), |
28 | }); | 32 | }); |
29 | // Initialize all stores | 33 | // Initialize all stores |