diff options
Diffstat (limited to 'packages/main/src/stores/MainStore.ts')
-rw-r--r-- | packages/main/src/stores/MainStore.ts | 127 |
1 files changed, 91 insertions, 36 deletions
diff --git a/packages/main/src/stores/MainStore.ts b/packages/main/src/stores/MainStore.ts index 9ac56f4..1abd20c 100644 --- a/packages/main/src/stores/MainStore.ts +++ b/packages/main/src/stores/MainStore.ts | |||
@@ -18,31 +18,27 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import type { Action, BrowserViewBounds } from '@sophie/shared'; | 21 | import type { Action } from '@sophie/shared'; |
22 | import { applySnapshot, Instance, types } from 'mobx-state-tree'; | 22 | import type { ResourceKey } from 'i18next'; |
23 | import { flow, Instance, types } from 'mobx-state-tree'; | ||
23 | 24 | ||
24 | import type { MainWindow } from '../infrastructure/electron/types'; | 25 | import type I18nStore from '../i18n/I18nStore.js'; |
25 | import { getLogger } from '../utils/log'; | 26 | import type { UseTranslationResult } from '../i18n/I18nStore.js'; |
27 | import type { MainWindow } from '../infrastructure/electron/types.js'; | ||
28 | import getLogger from '../utils/getLogger.js'; | ||
26 | 29 | ||
27 | import GlobalSettings from './GlobalSettings'; | 30 | import GlobalSettings from './GlobalSettings.js'; |
28 | import Profile from './Profile'; | 31 | import { getEnv } from './MainEnv.js'; |
29 | import Service from './Service'; | 32 | import Profile from './Profile.js'; |
30 | import SharedStore from './SharedStore'; | 33 | import Service from './Service.js'; |
34 | import SharedStore from './SharedStore.js'; | ||
31 | 35 | ||
32 | const log = getLogger('MainStore'); | 36 | const log = getLogger('MainStore'); |
33 | 37 | ||
34 | const MainStore = types | 38 | const MainStore = types |
35 | .model('MainStore', { | 39 | .model('MainStore', { |
36 | browserViewBounds: types.optional( | ||
37 | types.model('BrowserViewBounds', { | ||
38 | x: 0, | ||
39 | y: 0, | ||
40 | width: 0, | ||
41 | height: 0, | ||
42 | }), | ||
43 | {}, | ||
44 | ), | ||
45 | shared: types.optional(SharedStore, {}), | 40 | shared: types.optional(SharedStore, {}), |
41 | i18n: types.frozen<I18nStore | undefined>(), | ||
46 | }) | 42 | }) |
47 | .views((self) => ({ | 43 | .views((self) => ({ |
48 | get settings(): GlobalSettings { | 44 | get settings(): GlobalSettings { |
@@ -56,10 +52,19 @@ const MainStore = types | |||
56 | }, | 52 | }, |
57 | get visibleService(): Service | undefined { | 53 | get visibleService(): Service | undefined { |
58 | const { selectedService } = this.settings; | 54 | const { selectedService } = this.settings; |
59 | return selectedService !== undefined && selectedService.shouldBeLoaded | 55 | return selectedService !== undefined && selectedService.shouldBeVisible |
60 | ? selectedService | 56 | ? selectedService |
61 | : undefined; | 57 | : undefined; |
62 | }, | 58 | }, |
59 | useTranslation(ns?: string): UseTranslationResult { | ||
60 | return self.i18n?.useTranslation(ns) ?? { ready: false }; | ||
61 | }, | ||
62 | getTranslation(language: string, namespace: string): Promise<ResourceKey> { | ||
63 | if (self.i18n === undefined) { | ||
64 | throw new Error('i18next has not been set'); | ||
65 | } | ||
66 | return self.i18n.getTranslation(language, namespace); | ||
67 | }, | ||
63 | })) | 68 | })) |
64 | .volatile( | 69 | .volatile( |
65 | (): { | 70 | (): { |
@@ -69,34 +74,88 @@ const MainStore = types | |||
69 | }), | 74 | }), |
70 | ) | 75 | ) |
71 | .actions((self) => ({ | 76 | .actions((self) => ({ |
72 | setBrowserViewBounds(bounds: BrowserViewBounds): void { | 77 | setMainWindow(mainWindow: MainWindow | undefined): void { |
73 | applySnapshot(self.browserViewBounds, bounds); | 78 | self.mainWindow = mainWindow; |
79 | }, | ||
80 | openWebpageInBrowser() { | ||
81 | getEnv(self).openURLInExternalBrowser( | ||
82 | 'https://gitlab.com/say-hi-to-sophie/shophie', | ||
83 | ); | ||
84 | }, | ||
85 | openAboutDialog() { | ||
86 | getEnv(self).openAboutDialog(); | ||
87 | }, | ||
88 | beforeDestroy(): void { | ||
89 | self.mainWindow?.dispose(); | ||
90 | }, | ||
91 | setI18n(i18n: I18nStore): void { | ||
92 | self.i18n = i18n; | ||
93 | }, | ||
94 | addMissingTranslation( | ||
95 | languages: string[], | ||
96 | namespace: string, | ||
97 | key: string, | ||
98 | value: string, | ||
99 | ): void { | ||
100 | self.i18n?.addMissingTranslation(languages, namespace, key, value); | ||
74 | }, | 101 | }, |
102 | reloadTranslations: flow(function* reloadTranslations() { | ||
103 | if (self.i18n !== undefined) { | ||
104 | yield self.i18n.reloadTranslations(); | ||
105 | self.mainWindow?.reloadTranslations(); | ||
106 | } | ||
107 | }), | ||
108 | })) | ||
109 | .actions((self) => ({ | ||
75 | dispatch(action: Action): void { | 110 | dispatch(action: Action): void { |
76 | switch (action.action) { | 111 | switch (action.action) { |
77 | case 'reload-all-services': | ||
78 | // TODO | ||
79 | break; | ||
80 | case 'set-browser-view-bounds': | ||
81 | this.setBrowserViewBounds(action.browserViewBounds); | ||
82 | break; | ||
83 | case 'set-selected-service-id': | 112 | case 'set-selected-service-id': |
84 | self.settings.setSelectedServiceId(action.serviceId); | 113 | self.settings.setSelectedServiceId(action.serviceId); |
85 | break; | 114 | break; |
86 | case 'set-theme-source': | 115 | case 'set-theme-source': |
87 | self.settings.setThemeSource(action.themeSource); | 116 | self.settings.setThemeSource(action.themeSource); |
88 | break; | 117 | break; |
118 | case 'set-show-location-bar': | ||
119 | self.settings.setShowLocationBar(action.showLocationBar); | ||
120 | break; | ||
121 | case 'reload-all-services': | ||
122 | self.services.forEach((service) => service.reload()); | ||
123 | break; | ||
124 | case 'reload-all-translations': | ||
125 | if (self.i18n !== undefined) { | ||
126 | self.reloadTranslations().catch((error) => { | ||
127 | log.error('Failed to reload translations', error); | ||
128 | }); | ||
129 | } | ||
130 | break; | ||
131 | case 'add-missing-translation': | ||
132 | self.addMissingTranslation( | ||
133 | action.languages, | ||
134 | action.namespace, | ||
135 | action.key, | ||
136 | action.value, | ||
137 | ); | ||
138 | break; | ||
139 | case 'dispatch-service-action': { | ||
140 | const { serviceId, serviceAction } = action; | ||
141 | const service = self.shared.servicesById.get(serviceId); | ||
142 | if (service === undefined) { | ||
143 | log.error( | ||
144 | 'No such service', | ||
145 | serviceId, | ||
146 | 'to dispatch action', | ||
147 | serviceAction, | ||
148 | ); | ||
149 | } else { | ||
150 | service.dispatch(serviceAction); | ||
151 | } | ||
152 | break; | ||
153 | } | ||
89 | default: | 154 | default: |
90 | log.error('Unknown action to dispatch', action); | 155 | log.error('Unknown action to dispatch', action); |
91 | break; | 156 | break; |
92 | } | 157 | } |
93 | }, | 158 | }, |
94 | setMainWindow(mainWindow: MainWindow | undefined): void { | ||
95 | self.mainWindow = mainWindow; | ||
96 | }, | ||
97 | beforeDestroy(): void { | ||
98 | self.mainWindow?.dispose(); | ||
99 | }, | ||
100 | })); | 159 | })); |
101 | 160 | ||
102 | /* | 161 | /* |
@@ -106,7 +165,3 @@ const MainStore = types | |||
106 | interface MainStore extends Instance<typeof MainStore> {} | 165 | interface MainStore extends Instance<typeof MainStore> {} |
107 | 166 | ||
108 | export default MainStore; | 167 | export default MainStore; |
109 | |||
110 | export function createMainStore(): MainStore { | ||
111 | return MainStore.create(); | ||
112 | } | ||