diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-01-28 01:07:56 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-02-08 21:43:18 +0100 |
commit | 24bbe1f574ee6b0d6d0ebc8c29cbf014fc450584 (patch) | |
tree | e89b2d700930d6722eb0685d8d3a9be91df851cf /packages | |
parent | test: Add tests for main window hardening (diff) | |
download | sophie-24bbe1f574ee6b0d6d0ebc8c29cbf014fc450584.tar.gz sophie-24bbe1f574ee6b0d6d0ebc8c29cbf014fc450584.tar.zst sophie-24bbe1f574ee6b0d6d0ebc8c29cbf014fc450584.zip |
feat: Save selected service to file
Sophie start off from the service that was selected when it was last
open.
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages')
-rw-r--r-- | packages/main/src/index.ts | 2 | ||||
-rw-r--r-- | packages/main/src/infrastructure/config/impl/ConfigFile.ts | 4 | ||||
-rw-r--r-- | packages/main/src/reactions/synchronizeConfig.ts | 5 | ||||
-rw-r--r-- | packages/main/src/stores/GlobalSettings.ts | 22 | ||||
-rw-r--r-- | packages/main/src/stores/SharedStore.ts | 13 | ||||
-rw-r--r-- | packages/main/src/stores/config/loadConfig.ts | 28 | ||||
-rw-r--r-- | packages/renderer/src/components/ServiceSwitcher.tsx | 5 | ||||
-rw-r--r-- | packages/renderer/src/stores/RendererStore.ts | 7 | ||||
-rw-r--r-- | packages/shared/src/stores/GlobalSettings.ts | 3 | ||||
-rw-r--r-- | packages/shared/src/stores/SharedStore.ts | 1 |
10 files changed, 49 insertions, 41 deletions
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index 2072017..f5f6be4 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -205,7 +205,7 @@ async function createWindow(): Promise<unknown> { | |||
205 | const actionToDispatch = Action.parse(rawAction); | 205 | const actionToDispatch = Action.parse(rawAction); |
206 | switch (actionToDispatch.action) { | 206 | switch (actionToDispatch.action) { |
207 | case 'set-selected-service-id': | 207 | case 'set-selected-service-id': |
208 | store.shared.setSelectedServiceId(actionToDispatch.serviceId); | 208 | store.settings.setSelectedServiceId(actionToDispatch.serviceId); |
209 | break; | 209 | break; |
210 | case 'set-browser-view-bounds': | 210 | case 'set-browser-view-bounds': |
211 | store.setBrowserViewBounds(actionToDispatch.browserViewBounds); | 211 | store.setBrowserViewBounds(actionToDispatch.browserViewBounds); |
diff --git a/packages/main/src/infrastructure/config/impl/ConfigFile.ts b/packages/main/src/infrastructure/config/impl/ConfigFile.ts index 90ee187..e8237b4 100644 --- a/packages/main/src/infrastructure/config/impl/ConfigFile.ts +++ b/packages/main/src/infrastructure/config/impl/ConfigFile.ts | |||
@@ -29,7 +29,7 @@ import type Config from '../../../stores/config/Config'; | |||
29 | import type Disposer from '../../../utils/Disposer'; | 29 | import type Disposer from '../../../utils/Disposer'; |
30 | import { getLogger } from '../../../utils/log'; | 30 | import { getLogger } from '../../../utils/log'; |
31 | import type ConfigRepository from '../ConfigRepository'; | 31 | import type ConfigRepository from '../ConfigRepository'; |
32 | import type ReadConfigResult from '../ReadConfigResult'; | 32 | import type { ReadConfigResult } from '../ConfigRepository'; |
33 | 33 | ||
34 | const log = getLogger('ConfigFile'); | 34 | const log = getLogger('ConfigFile'); |
35 | 35 | ||
@@ -81,7 +81,7 @@ export default class ConfigFile implements ConfigRepository { | |||
81 | } finally { | 81 | } finally { |
82 | this.#writingConfig = false; | 82 | this.#writingConfig = false; |
83 | } | 83 | } |
84 | log.info('Wrote config file', this.#configFilePath); | 84 | log.debug('Wrote config file', this.#configFilePath); |
85 | } | 85 | } |
86 | 86 | ||
87 | watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer { | 87 | watchConfig(callback: () => Promise<void>, throttleMs: number): Disposer { |
diff --git a/packages/main/src/reactions/synchronizeConfig.ts b/packages/main/src/reactions/synchronizeConfig.ts index 4a9c24b..9436c16 100644 --- a/packages/main/src/reactions/synchronizeConfig.ts +++ b/packages/main/src/reactions/synchronizeConfig.ts | |||
@@ -58,6 +58,9 @@ export default async function synchronizeConfig( | |||
58 | return true; | 58 | return true; |
59 | } | 59 | } |
60 | lastConfigOnDisk = sharedStore.config; | 60 | lastConfigOnDisk = sharedStore.config; |
61 | // We can't use `comparer.structural` from `mobx`, because | ||
62 | // it handles missing values and `undefined` values differently, | ||
63 | // but JSON5 is unable to distinguish them. | ||
61 | if (!deepEqual(result.data, lastConfigOnDisk, { strict: true })) { | 64 | if (!deepEqual(result.data, lastConfigOnDisk, { strict: true })) { |
62 | await writeConfig(); | 65 | await writeConfig(); |
63 | } | 66 | } |
@@ -75,7 +78,7 @@ export default async function synchronizeConfig( | |||
75 | () => sharedStore.config, | 78 | () => sharedStore.config, |
76 | debounce((config) => { | 79 | debounce((config) => { |
77 | // We can compare snapshots by reference, since it is only recreated on store changes. | 80 | // We can compare snapshots by reference, since it is only recreated on store changes. |
78 | if (lastConfigOnDisk !== config) { | 81 | if (!deepEqual(config, lastConfigOnDisk, { strict: true })) { |
79 | writeConfig().catch((error) => { | 82 | writeConfig().catch((error) => { |
80 | log.error('Failed to write config on config change', error); | 83 | log.error('Failed to write config on config change', error); |
81 | }); | 84 | }); |
diff --git a/packages/main/src/stores/GlobalSettings.ts b/packages/main/src/stores/GlobalSettings.ts index 0a54aa3..7bbc089 100644 --- a/packages/main/src/stores/GlobalSettings.ts +++ b/packages/main/src/stores/GlobalSettings.ts | |||
@@ -22,12 +22,30 @@ import { | |||
22 | GlobalSettings as GlobalSettingsBase, | 22 | GlobalSettings as GlobalSettingsBase, |
23 | ThemeSource, | 23 | ThemeSource, |
24 | } from '@sophie/shared'; | 24 | } from '@sophie/shared'; |
25 | import { Instance } from 'mobx-state-tree'; | 25 | import { Instance, resolveIdentifier, types } from 'mobx-state-tree'; |
26 | 26 | ||
27 | const GlobalSettings = GlobalSettingsBase.actions((self) => ({ | 27 | import { getLogger } from '../utils/log'; |
28 | import overrideProps from '../utils/overrideProps'; | ||
29 | |||
30 | import Service from './Service'; | ||
31 | |||
32 | const log = getLogger('sharedStore'); | ||
33 | |||
34 | const GlobalSettings = overrideProps(GlobalSettingsBase, { | ||
35 | selectedService: types.safeReference(Service), | ||
36 | }).actions((self) => ({ | ||
28 | setThemeSource(mode: ThemeSource): void { | 37 | setThemeSource(mode: ThemeSource): void { |
29 | self.themeSource = mode; | 38 | self.themeSource = mode; |
30 | }, | 39 | }, |
40 | setSelectedServiceId(serviceId: string): void { | ||
41 | const serviceInstance = resolveIdentifier(Service, self, serviceId); | ||
42 | if (serviceInstance === undefined) { | ||
43 | log.warn('Trying to select unknown service', serviceId); | ||
44 | return; | ||
45 | } | ||
46 | self.selectedService = serviceInstance; | ||
47 | log.debug('Selected service', serviceId); | ||
48 | }, | ||
31 | })); | 49 | })); |
32 | 50 | ||
33 | /* | 51 | /* |
diff --git a/packages/main/src/stores/SharedStore.ts b/packages/main/src/stores/SharedStore.ts index b9983f6..182b693 100644 --- a/packages/main/src/stores/SharedStore.ts +++ b/packages/main/src/stores/SharedStore.ts | |||
@@ -21,7 +21,6 @@ | |||
21 | import { SharedStore as SharedStoreBase } from '@sophie/shared'; | 21 | import { SharedStore as SharedStoreBase } from '@sophie/shared'; |
22 | import { getSnapshot, Instance, types } from 'mobx-state-tree'; | 22 | import { getSnapshot, Instance, types } from 'mobx-state-tree'; |
23 | 23 | ||
24 | import { getLogger } from '../utils/log'; | ||
25 | import overrideProps from '../utils/overrideProps'; | 24 | import overrideProps from '../utils/overrideProps'; |
26 | 25 | ||
27 | import GlobalSettings from './GlobalSettings'; | 26 | import GlobalSettings from './GlobalSettings'; |
@@ -30,8 +29,6 @@ import Service from './Service'; | |||
30 | import type Config from './config/Config'; | 29 | import type Config from './config/Config'; |
31 | import loadConfig from './config/loadConfig'; | 30 | import loadConfig from './config/loadConfig'; |
32 | 31 | ||
33 | const log = getLogger('sharedStore'); | ||
34 | |||
35 | function getConfigs<T>(models: { config: T }[]): T[] | undefined { | 32 | function getConfigs<T>(models: { config: T }[]): T[] | undefined { |
36 | return models.length === 0 ? undefined : models.map((model) => model.config); | 33 | return models.length === 0 ? undefined : models.map((model) => model.config); |
37 | } | 34 | } |
@@ -42,7 +39,6 @@ const SharedStore = overrideProps(SharedStoreBase, { | |||
42 | profiles: types.array(types.reference(Profile)), | 39 | profiles: types.array(types.reference(Profile)), |
43 | servicesById: types.map(Service), | 40 | servicesById: types.map(Service), |
44 | services: types.array(types.reference(Service)), | 41 | services: types.array(types.reference(Service)), |
45 | selectedService: types.safeReference(Service), | ||
46 | }) | 42 | }) |
47 | .views((self) => ({ | 43 | .views((self) => ({ |
48 | get config(): Config { | 44 | get config(): Config { |
@@ -62,15 +58,6 @@ const SharedStore = overrideProps(SharedStoreBase, { | |||
62 | setShouldUseDarkColors(shouldUseDarkColors: boolean): void { | 58 | setShouldUseDarkColors(shouldUseDarkColors: boolean): void { |
63 | self.shouldUseDarkColors = shouldUseDarkColors; | 59 | self.shouldUseDarkColors = shouldUseDarkColors; |
64 | }, | 60 | }, |
65 | setSelectedServiceId(serviceId: string): void { | ||
66 | const serviceInstance = self.servicesById.get(serviceId); | ||
67 | if (serviceInstance === undefined) { | ||
68 | log.warn('Trying to select unknown service', serviceId); | ||
69 | return; | ||
70 | } | ||
71 | self.selectedService = serviceInstance; | ||
72 | log.debug('Selected service', serviceId); | ||
73 | }, | ||
74 | })); | 61 | })); |
75 | 62 | ||
76 | /* | 63 | /* |
diff --git a/packages/main/src/stores/config/loadConfig.ts b/packages/main/src/stores/config/loadConfig.ts index 770d675..55d15c8 100644 --- a/packages/main/src/stores/config/loadConfig.ts +++ b/packages/main/src/stores/config/loadConfig.ts | |||
@@ -106,22 +106,13 @@ export default function loadConfig( | |||
106 | target: { | 106 | target: { |
107 | readonly profiles: IMSTArray<IReferenceType<typeof Profile>>; | 107 | readonly profiles: IMSTArray<IReferenceType<typeof Profile>>; |
108 | readonly profilesById: IMSTMap<typeof Profile>; | 108 | readonly profilesById: IMSTMap<typeof Profile>; |
109 | selectedService: Service | undefined; | ||
110 | readonly services: IMSTArray<IReferenceType<typeof Service>>; | 109 | readonly services: IMSTArray<IReferenceType<typeof Service>>; |
111 | readonly servicesById: IMSTMap<typeof Service>; | 110 | readonly servicesById: IMSTMap<typeof Service>; |
112 | readonly settings: GlobalSettings; | 111 | readonly settings: GlobalSettings; |
113 | }, | 112 | }, |
114 | config: Config, | 113 | config: Config, |
115 | ): void { | 114 | ): void { |
116 | const { | 115 | const { profiles, profilesById, services, servicesById, settings } = target; |
117 | profiles, | ||
118 | profilesById, | ||
119 | selectedService, | ||
120 | services, | ||
121 | servicesById, | ||
122 | settings, | ||
123 | } = target; | ||
124 | const { id: selectedServiceId } = selectedService ?? { id: undefined }; | ||
125 | const { | 116 | const { |
126 | profiles: profilesConfig, | 117 | profiles: profilesConfig, |
127 | services: servicesConfig, | 118 | services: servicesConfig, |
@@ -134,13 +125,16 @@ export default function loadConfig( | |||
134 | ); | 125 | ); |
135 | applySettings(profiles, profilesById, profilesToApply); | 126 | applySettings(profiles, profilesById, profilesToApply); |
136 | applySettings(services, servicesById, servicesToApply); | 127 | applySettings(services, servicesById, servicesToApply); |
137 | applySnapshot(settings, settingsToApply); | 128 | const { selectedService } = settingsToApply; |
138 | let newSelectedService: Service | undefined; | 129 | // Be more robust against when a deleted service is selected. |
139 | if (selectedServiceId !== undefined) { | 130 | if ( |
140 | newSelectedService = servicesById.get(selectedServiceId); | 131 | typeof selectedService !== 'string' || |
132 | !servicesById.has(selectedService) | ||
133 | ) { | ||
134 | settingsToApply.selectedService = undefined; | ||
141 | } | 135 | } |
142 | if (newSelectedService === undefined && services.length > 0) { | 136 | applySnapshot(settings, settingsToApply); |
143 | [newSelectedService] = services; | 137 | if (settings.selectedService === undefined && services.length > 0) { |
138 | [settings.selectedService] = services; | ||
144 | } | 139 | } |
145 | target.selectedService = newSelectedService; | ||
146 | } | 140 | } |
diff --git a/packages/renderer/src/components/ServiceSwitcher.tsx b/packages/renderer/src/components/ServiceSwitcher.tsx index 167153f..e4d371e 100644 --- a/packages/renderer/src/components/ServiceSwitcher.tsx +++ b/packages/renderer/src/components/ServiceSwitcher.tsx | |||
@@ -63,7 +63,10 @@ const ServiceSwitcherTab = styled(Tab, { | |||
63 | 63 | ||
64 | export default observer(() => { | 64 | export default observer(() => { |
65 | const store = useStore(); | 65 | const store = useStore(); |
66 | const { selectedService, services } = store; | 66 | const { |
67 | settings: { selectedService }, | ||
68 | services, | ||
69 | } = store; | ||
67 | 70 | ||
68 | return ( | 71 | return ( |
69 | <ServiceSwitcherRoot | 72 | <ServiceSwitcherRoot |
diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts index c5a94df..4d85929 100644 --- a/packages/renderer/src/stores/RendererStore.ts +++ b/packages/renderer/src/stores/RendererStore.ts | |||
@@ -24,6 +24,7 @@ import { | |||
24 | Service, | 24 | Service, |
25 | SophieRenderer, | 25 | SophieRenderer, |
26 | ThemeSource, | 26 | ThemeSource, |
27 | GlobalSettings, | ||
27 | } from '@sophie/shared'; | 28 | } from '@sophie/shared'; |
28 | import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree'; | 29 | import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree'; |
29 | 30 | ||
@@ -38,12 +39,12 @@ const RendererStore = types | |||
38 | shared: types.optional(SharedStore, {}), | 39 | shared: types.optional(SharedStore, {}), |
39 | }) | 40 | }) |
40 | .views((self) => ({ | 41 | .views((self) => ({ |
42 | get settings(): GlobalSettings { | ||
43 | return self.shared.settings; | ||
44 | }, | ||
41 | get services(): Service[] { | 45 | get services(): Service[] { |
42 | return self.shared.services; | 46 | return self.shared.services; |
43 | }, | 47 | }, |
44 | get selectedService(): Service | undefined { | ||
45 | return self.shared.selectedService; | ||
46 | }, | ||
47 | })) | 48 | })) |
48 | .actions((self) => ({ | 49 | .actions((self) => ({ |
49 | setSelectedServiceId(serviceId: string): void { | 50 | setSelectedServiceId(serviceId: string): void { |
diff --git a/packages/shared/src/stores/GlobalSettings.ts b/packages/shared/src/stores/GlobalSettings.ts index 1c6d7f3..7a2c334 100644 --- a/packages/shared/src/stores/GlobalSettings.ts +++ b/packages/shared/src/stores/GlobalSettings.ts | |||
@@ -22,12 +22,15 @@ import { Instance, types, SnapshotIn, SnapshotOut } from 'mobx-state-tree'; | |||
22 | 22 | ||
23 | import { ThemeSource } from '../schemas'; | 23 | import { ThemeSource } from '../schemas'; |
24 | 24 | ||
25 | import Service from './Service'; | ||
26 | |||
25 | const GlobalSettings = /* @__PURE__ */ (() => | 27 | const GlobalSettings = /* @__PURE__ */ (() => |
26 | types.model('GlobalSettings', { | 28 | types.model('GlobalSettings', { |
27 | themeSource: types.optional( | 29 | themeSource: types.optional( |
28 | types.enumeration(ThemeSource.options), | 30 | types.enumeration(ThemeSource.options), |
29 | 'system', | 31 | 'system', |
30 | ), | 32 | ), |
33 | selectedService: types.safeReference(Service), | ||
31 | }))(); | 34 | }))(); |
32 | 35 | ||
33 | /* | 36 | /* |
diff --git a/packages/shared/src/stores/SharedStore.ts b/packages/shared/src/stores/SharedStore.ts index 4e064c6..d81a3d3 100644 --- a/packages/shared/src/stores/SharedStore.ts +++ b/packages/shared/src/stores/SharedStore.ts | |||
@@ -37,7 +37,6 @@ const SharedStore = /* @__PURE__ */ (() => | |||
37 | profiles: types.array(types.reference(Profile)), | 37 | profiles: types.array(types.reference(Profile)), |
38 | servicesById: types.map(Service), | 38 | servicesById: types.map(Service), |
39 | services: types.array(types.reference(Service)), | 39 | services: types.array(types.reference(Service)), |
40 | selectedService: types.safeReference(Service), | ||
41 | shouldUseDarkColors: false, | 40 | shouldUseDarkColors: false, |
42 | }))(); | 41 | }))(); |
43 | 42 | ||