aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/main/src/stores/GlobalSettings.ts12
-rw-r--r--packages/main/src/stores/Profile.ts7
-rw-r--r--packages/main/src/stores/Service.ts7
-rw-r--r--packages/main/src/stores/ServiceSettings.ts10
-rw-r--r--packages/main/src/stores/SharedStore.ts14
-rw-r--r--packages/main/src/stores/config/loadConfig.ts2
-rw-r--r--packages/main/src/utils/overrideProps.ts62
-rw-r--r--packages/renderer/src/components/locationBar/LocationTextField.tsx3
-rw-r--r--packages/renderer/src/components/locationBar/NavigationButtons.tsx3
-rw-r--r--packages/renderer/src/components/sidebar/ServiceIcon.tsx3
-rw-r--r--packages/renderer/src/components/sidebar/ServiceSwitcher.tsx9
-rw-r--r--packages/renderer/src/components/sidebar/ToggleDarkModeButton.tsx8
-rw-r--r--packages/renderer/src/components/sidebar/ToggleLocationBarButton.tsx8
-rw-r--r--packages/renderer/src/stores/GlobalSettings.ts63
-rw-r--r--packages/renderer/src/stores/Profile.ts (renamed from packages/main/src/stores/ProfileSettings.ts)18
-rw-r--r--packages/renderer/src/stores/RendererStore.ts41
-rw-r--r--packages/renderer/src/stores/Service.ts34
-rw-r--r--packages/renderer/src/stores/ServiceSettings.ts (renamed from packages/shared/src/stores/ServiceSettings.ts)20
-rw-r--r--packages/renderer/src/stores/SharedStore.ts (renamed from packages/shared/src/stores/SharedStore.ts)47
-rw-r--r--packages/shared/src/contextBridge/SophieRenderer.ts2
-rw-r--r--packages/shared/src/index.ts26
-rw-r--r--packages/shared/src/stores/GlobalSettingsBase.ts (renamed from packages/shared/src/stores/GlobalSettings.ts)32
-rw-r--r--packages/shared/src/stores/ServiceBase.ts (renamed from packages/shared/src/stores/Service.ts)20
-rw-r--r--packages/shared/src/stores/ServiceSettingsBase.ts57
-rw-r--r--packages/shared/src/stores/SharedStoreBase.ts70
25 files changed, 348 insertions, 230 deletions
diff --git a/packages/main/src/stores/GlobalSettings.ts b/packages/main/src/stores/GlobalSettings.ts
index 2af9da2..31b7e12 100644
--- a/packages/main/src/stores/GlobalSettings.ts
+++ b/packages/main/src/stores/GlobalSettings.ts
@@ -18,22 +18,16 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { 21import { defineGlobalSettingsModel, ThemeSource } from '@sophie/shared';
22 GlobalSettings as GlobalSettingsBase, 22import { Instance, resolveIdentifier } from 'mobx-state-tree';
23 ThemeSource,
24} from '@sophie/shared';
25import { Instance, resolveIdentifier, types } from 'mobx-state-tree';
26 23
27import { getLogger } from '../utils/log'; 24import { getLogger } from '../utils/log';
28import overrideProps from '../utils/overrideProps';
29 25
30import Service from './Service'; 26import Service from './Service';
31 27
32const log = getLogger('sharedStore'); 28const log = getLogger('sharedStore');
33 29
34const GlobalSettings = overrideProps(GlobalSettingsBase, { 30const GlobalSettings = defineGlobalSettingsModel(Service).actions((self) => ({
35 selectedService: types.safeReference(Service),
36}).actions((self) => ({
37 setThemeSource(mode: ThemeSource): void { 31 setThemeSource(mode: ThemeSource): void {
38 self.themeSource = mode; 32 self.themeSource = mode;
39 }, 33 },
diff --git a/packages/main/src/stores/Profile.ts b/packages/main/src/stores/Profile.ts
index 0fd486e..836f4a8 100644
--- a/packages/main/src/stores/Profile.ts
+++ b/packages/main/src/stores/Profile.ts
@@ -21,14 +21,9 @@
21import { Profile as ProfileBase } from '@sophie/shared'; 21import { Profile as ProfileBase } from '@sophie/shared';
22import { getSnapshot, Instance } from 'mobx-state-tree'; 22import { getSnapshot, Instance } from 'mobx-state-tree';
23 23
24import overrideProps from '../utils/overrideProps';
25
26import ProfileSettings from './ProfileSettings';
27import type ProfileConfig from './config/ProfileConfig'; 24import type ProfileConfig from './config/ProfileConfig';
28 25
29const Profile = overrideProps(ProfileBase, { 26const Profile = ProfileBase.views((self) => ({
30 settings: ProfileSettings,
31}).views((self) => ({
32 get config(): ProfileConfig { 27 get config(): ProfileConfig {
33 const { id, settings } = self; 28 const { id, settings } = self;
34 return { ...getSnapshot(settings), id }; 29 return { ...getSnapshot(settings), id };
diff --git a/packages/main/src/stores/Service.ts b/packages/main/src/stores/Service.ts
index 5302dd4..abef7c2 100644
--- a/packages/main/src/stores/Service.ts
+++ b/packages/main/src/stores/Service.ts
@@ -19,18 +19,15 @@
19 */ 19 */
20 20
21import type { UnreadCount } from '@sophie/service-shared'; 21import type { UnreadCount } from '@sophie/service-shared';
22import { Service as ServiceBase } from '@sophie/shared'; 22import { defineServiceModel } from '@sophie/shared';
23import { Instance, getSnapshot } from 'mobx-state-tree'; 23import { Instance, getSnapshot } from 'mobx-state-tree';
24 24
25import type { ServiceView } from '../infrastructure/electron/types'; 25import type { ServiceView } from '../infrastructure/electron/types';
26import overrideProps from '../utils/overrideProps';
27 26
28import ServiceSettings from './ServiceSettings'; 27import ServiceSettings from './ServiceSettings';
29import type ServiceConfig from './config/ServiceConfig'; 28import type ServiceConfig from './config/ServiceConfig';
30 29
31const Service = overrideProps(ServiceBase, { 30const Service = defineServiceModel(ServiceSettings)
32 settings: ServiceSettings,
33})
34 .views((self) => ({ 31 .views((self) => ({
35 get config(): ServiceConfig { 32 get config(): ServiceConfig {
36 const { id, settings } = self; 33 const { id, settings } = self;
diff --git a/packages/main/src/stores/ServiceSettings.ts b/packages/main/src/stores/ServiceSettings.ts
index e6f48c6..5d37347 100644
--- a/packages/main/src/stores/ServiceSettings.ts
+++ b/packages/main/src/stores/ServiceSettings.ts
@@ -18,16 +18,12 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { ServiceSettings as ServiceSettingsBase } from '@sophie/shared'; 21import { defineServiceSettingsModel } from '@sophie/shared';
22import { Instance, types } from 'mobx-state-tree'; 22import { Instance } from 'mobx-state-tree';
23
24import overrideProps from '../utils/overrideProps';
25 23
26import Profile from './Profile'; 24import Profile from './Profile';
27 25
28const ServiceSettings = overrideProps(ServiceSettingsBase, { 26const ServiceSettings = defineServiceSettingsModel(Profile);
29 profile: types.reference(Profile),
30});
31 27
32/* 28/*
33 eslint-disable-next-line @typescript-eslint/no-redeclare -- 29 eslint-disable-next-line @typescript-eslint/no-redeclare --
diff --git a/packages/main/src/stores/SharedStore.ts b/packages/main/src/stores/SharedStore.ts
index 182b693..d72c532 100644
--- a/packages/main/src/stores/SharedStore.ts
+++ b/packages/main/src/stores/SharedStore.ts
@@ -18,10 +18,8 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { SharedStore as SharedStoreBase } from '@sophie/shared'; 21import { defineSharedStoreModel } from '@sophie/shared';
22import { getSnapshot, Instance, types } from 'mobx-state-tree'; 22import { getSnapshot, Instance } from 'mobx-state-tree';
23
24import overrideProps from '../utils/overrideProps';
25 23
26import GlobalSettings from './GlobalSettings'; 24import GlobalSettings from './GlobalSettings';
27import Profile from './Profile'; 25import Profile from './Profile';
@@ -33,13 +31,7 @@ function getConfigs<T>(models: { config: T }[]): T[] | undefined {
33 return models.length === 0 ? undefined : models.map((model) => model.config); 31 return models.length === 0 ? undefined : models.map((model) => model.config);
34} 32}
35 33
36const SharedStore = overrideProps(SharedStoreBase, { 34const SharedStore = defineSharedStoreModel(GlobalSettings, Profile, Service)
37 settings: types.optional(GlobalSettings, {}),
38 profilesById: types.map(Profile),
39 profiles: types.array(types.reference(Profile)),
40 servicesById: types.map(Service),
41 services: types.array(types.reference(Service)),
42})
43 .views((self) => ({ 35 .views((self) => ({
44 get config(): Config { 36 get config(): Config {
45 const { settings, profiles, services } = self; 37 const { settings, profiles, services } = self;
diff --git a/packages/main/src/stores/config/loadConfig.ts b/packages/main/src/stores/config/loadConfig.ts
index 55d15c8..2463084 100644
--- a/packages/main/src/stores/config/loadConfig.ts
+++ b/packages/main/src/stores/config/loadConfig.ts
@@ -18,6 +18,7 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { ProfileSettingsSnapshotIn } from '@sophie/shared';
21import { 22import {
22 applySnapshot, 23 applySnapshot,
23 IMSTArray, 24 IMSTArray,
@@ -31,7 +32,6 @@ import slug from 'slug';
31 32
32import GlobalSettings from '../GlobalSettings'; 33import GlobalSettings from '../GlobalSettings';
33import type Profile from '../Profile'; 34import type Profile from '../Profile';
34import type { ProfileSettingsSnapshotIn } from '../ProfileSettings';
35import type Service from '../Service'; 35import type Service from '../Service';
36import type { ServiceSettingsSnapshotIn } from '../ServiceSettings'; 36import type { ServiceSettingsSnapshotIn } from '../ServiceSettings';
37 37
diff --git a/packages/main/src/utils/overrideProps.ts b/packages/main/src/utils/overrideProps.ts
deleted file mode 100644
index c626408..0000000
--- a/packages/main/src/utils/overrideProps.ts
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21/**
22 * @file This file implements a technique to force-override properties of a model.
23 *
24 * The overridden properties must conform to the SnapshotIt and SnapshotOut format
25 * of the original model. Essentially, this means that only views and actions can
26 * be added safely.
27 *
28 * @see https://github.com/mobxjs/mobx-state-tree/issues/1403#issuecomment-940843087
29 */
30
31import {
32 IAnyModelType,
33 IModelType,
34 ModelProperties,
35 SnapshotIn,
36 SnapshotOut,
37} from 'mobx-state-tree';
38
39export type IUnsafeOverriddenModelType<
40 BASE extends IAnyModelType,
41 PROPS extends ModelProperties,
42> = BASE extends IModelType<infer P, infer O, infer CC, infer CS>
43 ? IModelType<Omit<P, keyof PROPS> & PROPS, O, CC, CS>
44 : never;
45
46export type IOverriddenModelType<
47 BASE extends IAnyModelType,
48 PROPS extends ModelProperties,
49> = SnapshotIn<BASE> extends SnapshotIn<IUnsafeOverriddenModelType<BASE, PROPS>>
50 ? SnapshotOut<
51 IUnsafeOverriddenModelType<BASE, PROPS>
52 > extends SnapshotOut<BASE>
53 ? IUnsafeOverriddenModelType<BASE, PROPS>
54 : never
55 : never;
56
57export default function overrideProps<
58 BASE extends IAnyModelType,
59 PROPS extends ModelProperties,
60>(base: BASE, props: PROPS): IOverriddenModelType<BASE, PROPS> {
61 return base.props(props) as IOverriddenModelType<BASE, PROPS>;
62}
diff --git a/packages/renderer/src/components/locationBar/LocationTextField.tsx b/packages/renderer/src/components/locationBar/LocationTextField.tsx
index f436bf0..e6da59f 100644
--- a/packages/renderer/src/components/locationBar/LocationTextField.tsx
+++ b/packages/renderer/src/components/locationBar/LocationTextField.tsx
@@ -20,11 +20,12 @@
20 20
21import FilledInput from '@mui/material/FilledInput'; 21import FilledInput from '@mui/material/FilledInput';
22import { styled } from '@mui/material/styles'; 22import { styled } from '@mui/material/styles';
23import { Service } from '@sophie/shared';
24import { autorun } from 'mobx'; 23import { autorun } from 'mobx';
25import { observer } from 'mobx-react-lite'; 24import { observer } from 'mobx-react-lite';
26import React, { useCallback, useEffect, useState } from 'react'; 25import React, { useCallback, useEffect, useState } from 'react';
27 26
27import Service from '../../stores/Service';
28
28import GoAdornment from './GoAdornment'; 29import GoAdornment from './GoAdornment';
29import LocationOverlayInput from './LocationOverlayInput'; 30import LocationOverlayInput from './LocationOverlayInput';
30import UrlAdornment from './UrlAdornment'; 31import UrlAdornment from './UrlAdornment';
diff --git a/packages/renderer/src/components/locationBar/NavigationButtons.tsx b/packages/renderer/src/components/locationBar/NavigationButtons.tsx
index 77b02b6..ce59692 100644
--- a/packages/renderer/src/components/locationBar/NavigationButtons.tsx
+++ b/packages/renderer/src/components/locationBar/NavigationButtons.tsx
@@ -26,10 +26,11 @@ import IconRefresh from '@mui/icons-material/Refresh';
26import { useTheme } from '@mui/material'; 26import { useTheme } from '@mui/material';
27import Box from '@mui/material/Box'; 27import Box from '@mui/material/Box';
28import IconButton from '@mui/material/IconButton'; 28import IconButton from '@mui/material/IconButton';
29import { Service } from '@sophie/shared';
30import { observer } from 'mobx-react-lite'; 29import { observer } from 'mobx-react-lite';
31import React from 'react'; 30import React from 'react';
32 31
32import Service from '../../stores/Service';
33
33function NavigationButtons({ 34function NavigationButtons({
34 service, 35 service,
35}: { 36}: {
diff --git a/packages/renderer/src/components/sidebar/ServiceIcon.tsx b/packages/renderer/src/components/sidebar/ServiceIcon.tsx
index 144f860..5db8a0c 100644
--- a/packages/renderer/src/components/sidebar/ServiceIcon.tsx
+++ b/packages/renderer/src/components/sidebar/ServiceIcon.tsx
@@ -20,10 +20,11 @@
20 20
21import Badge from '@mui/material/Badge'; 21import Badge from '@mui/material/Badge';
22import { styled, useTheme } from '@mui/material/styles'; 22import { styled, useTheme } from '@mui/material/styles';
23import { Service } from '@sophie/shared';
24import { observer } from 'mobx-react-lite'; 23import { observer } from 'mobx-react-lite';
25import React, { useEffect, useState } from 'react'; 24import React, { useEffect, useState } from 'react';
26 25
26import type Service from '../../stores/Service';
27
27const ServiceIconRoot = styled('div', { 28const ServiceIconRoot = styled('div', {
28 name: 'ServiceIcon', 29 name: 'ServiceIcon',
29 slot: 'Root', 30 slot: 'Root',
diff --git a/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx b/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx
index 2241476..eba21b5 100644
--- a/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx
+++ b/packages/renderer/src/components/sidebar/ServiceSwitcher.tsx
@@ -65,11 +65,8 @@ const ServiceSwitcherTab = styled(Tab, {
65})); 65}));
66 66
67function ServiceSwitcher(): JSX.Element { 67function ServiceSwitcher(): JSX.Element {
68 const store = useStore(); 68 const { settings, services } = useStore();
69 const { 69 const { selectedService } = settings;
70 settings: { selectedService },
71 services,
72 } = store;
73 70
74 return ( 71 return (
75 <ServiceSwitcherRoot 72 <ServiceSwitcherRoot
@@ -77,7 +74,7 @@ function ServiceSwitcher(): JSX.Element {
77 orientation="vertical" 74 orientation="vertical"
78 value={selectedService === undefined ? false : selectedService.id} 75 value={selectedService === undefined ? false : selectedService.id}
79 onChange={(_event, newValue: string) => 76 onChange={(_event, newValue: string) =>
80 store.setSelectedServiceId(newValue) 77 settings.setSelectedServiceId(newValue)
81 } 78 }
82 > 79 >
83 {services.map((service) => ( 80 {services.map((service) => (
diff --git a/packages/renderer/src/components/sidebar/ToggleDarkModeButton.tsx b/packages/renderer/src/components/sidebar/ToggleDarkModeButton.tsx
index 164b066..bacbf07 100644
--- a/packages/renderer/src/components/sidebar/ToggleDarkModeButton.tsx
+++ b/packages/renderer/src/components/sidebar/ToggleDarkModeButton.tsx
@@ -27,15 +27,13 @@ import React from 'react';
27import { useStore } from '../StoreProvider'; 27import { useStore } from '../StoreProvider';
28 28
29export default observer(() => { 29export default observer(() => {
30 const store = useStore(); 30 const { shared } = useStore();
31 const { 31 const { shouldUseDarkColors } = shared;
32 shared: { shouldUseDarkColors },
33 } = store;
34 32
35 return ( 33 return (
36 <IconButton 34 <IconButton
37 aria-label="Toggle dark mode" 35 aria-label="Toggle dark mode"
38 onClick={() => store.toggleDarkMode()} 36 onClick={() => shared.toggleDarkMode()}
39 > 37 >
40 {shouldUseDarkColors ? <LightModeIcon /> : <DarkModeIcon />} 38 {shouldUseDarkColors ? <LightModeIcon /> : <DarkModeIcon />}
41 </IconButton> 39 </IconButton>
diff --git a/packages/renderer/src/components/sidebar/ToggleLocationBarButton.tsx b/packages/renderer/src/components/sidebar/ToggleLocationBarButton.tsx
index 60033b0..d2f0745 100644
--- a/packages/renderer/src/components/sidebar/ToggleLocationBarButton.tsx
+++ b/packages/renderer/src/components/sidebar/ToggleLocationBarButton.tsx
@@ -45,17 +45,15 @@ function ToggleLocationBarIcon({
45} 45}
46 46
47function ToggleLocationBarButton(): JSX.Element { 47function ToggleLocationBarButton(): JSX.Element {
48 const store = useStore(); 48 const { settings } = useStore();
49 const { 49 const { selectedService, showLocationBar } = settings;
50 settings: { selectedService, showLocationBar },
51 } = store;
52 50
53 return ( 51 return (
54 <IconButton 52 <IconButton
55 aria-pressed={showLocationBar} 53 aria-pressed={showLocationBar}
56 aria-controls={LOCATION_BAR_ID} 54 aria-controls={LOCATION_BAR_ID}
57 aria-label="Show location bar" 55 aria-label="Show location bar"
58 onClick={() => store.toggleLocationBar()} 56 onClick={() => settings.toggleLocationBar()}
59 > 57 >
60 <ToggleLocationBarIcon 58 <ToggleLocationBarIcon
61 loading={selectedService?.state === 'loading'} 59 loading={selectedService?.state === 'loading'}
diff --git a/packages/renderer/src/stores/GlobalSettings.ts b/packages/renderer/src/stores/GlobalSettings.ts
new file mode 100644
index 0000000..79815ba
--- /dev/null
+++ b/packages/renderer/src/stores/GlobalSettings.ts
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { defineGlobalSettingsModel, ThemeSource } from '@sophie/shared';
22import { Instance } from 'mobx-state-tree';
23
24import getEnv from '../env/getEnv';
25
26import Service from './Service';
27
28const GlobalSettings = defineGlobalSettingsModel(Service).actions((self) => ({
29 setSelectedServiceId(serviceId: string): void {
30 getEnv(self).dispatchMainAction({
31 action: 'set-selected-service-id',
32 serviceId,
33 });
34 },
35 setThemeSource(themeSource: ThemeSource): void {
36 getEnv(self).dispatchMainAction({
37 action: 'set-theme-source',
38 themeSource,
39 });
40 },
41 setShowLocationBar(showLocationBar: boolean): void {
42 getEnv(self).dispatchMainAction({
43 action: 'set-show-location-bar',
44 showLocationBar,
45 });
46 },
47 toggleLocationBar(): void {
48 this.setShowLocationBar(!self.showLocationBar);
49 },
50}));
51
52/*
53 eslint-disable-next-line @typescript-eslint/no-redeclare --
54 Intentionally naming the type the same as the store definition.
55*/
56interface GlobalSettings extends Instance<typeof GlobalSettings> {}
57
58export default GlobalSettings;
59
60export type {
61 GlobalSettingsSnapshotIn,
62 GlobalSettingsSnapshotOut,
63} from '@sophie/shared';
diff --git a/packages/main/src/stores/ProfileSettings.ts b/packages/renderer/src/stores/Profile.ts
index eed51e3..20a3a17 100644
--- a/packages/main/src/stores/ProfileSettings.ts
+++ b/packages/renderer/src/stores/Profile.ts
@@ -18,13 +18,15 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { ProfileSettings } from '@sophie/shared'; 21import { Profile as ProfileBase } from '@sophie/shared';
22import { Instance } from 'mobx-state-tree';
22 23
23// TODO Export a modified ProfileSettings once we need to add actions to it. 24const Profile = ProfileBase;
24// eslint-disable-next-line unicorn/prefer-export-from -- Can't export from default.
25export default ProfileSettings;
26 25
27export type { 26/*
28 ProfileSettingsSnapshotIn, 27 eslint-disable-next-line @typescript-eslint/no-redeclare --
29 ProfileSettingsSnapshotOut, 28 Intentionally naming the type the same as the store definition.
30} from '@sophie/shared'; 29*/
30interface Profile extends Instance<typeof Profile> {}
31
32export default Profile;
diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts
index 1acc605..8f424f6 100644
--- a/packages/renderer/src/stores/RendererStore.ts
+++ b/packages/renderer/src/stores/RendererStore.ts
@@ -18,20 +18,17 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { 21import { BrowserViewBounds, SophieRenderer } from '@sophie/shared';
22 BrowserViewBounds,
23 SharedStore,
24 Service,
25 SophieRenderer,
26 ThemeSource,
27 GlobalSettings,
28} from '@sophie/shared';
29import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree'; 22import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree';
30 23
31import RendererEnv from '../env/RendererEnv'; 24import RendererEnv from '../env/RendererEnv';
32import getEnv from '../env/getEnv'; 25import getEnv from '../env/getEnv';
33import { getLogger } from '../utils/log'; 26import { getLogger } from '../utils/log';
34 27
28import GlobalSettings from './GlobalSettings';
29import Service from './Service';
30import SharedStore from './SharedStore';
31
35const log = getLogger('RendererStore'); 32const log = getLogger('RendererStore');
36 33
37const RendererStore = types 34const RendererStore = types
@@ -47,40 +44,12 @@ const RendererStore = types
47 }, 44 },
48 })) 45 }))
49 .actions((self) => ({ 46 .actions((self) => ({
50 setSelectedServiceId(serviceId: string): void {
51 getEnv(self).dispatchMainAction({
52 action: 'set-selected-service-id',
53 serviceId,
54 });
55 },
56 setBrowserViewBounds(browserViewBounds: BrowserViewBounds): void { 47 setBrowserViewBounds(browserViewBounds: BrowserViewBounds): void {
57 getEnv(self).dispatchMainAction({ 48 getEnv(self).dispatchMainAction({
58 action: 'set-browser-view-bounds', 49 action: 'set-browser-view-bounds',
59 browserViewBounds, 50 browserViewBounds,
60 }); 51 });
61 }, 52 },
62 setThemeSource(themeSource: ThemeSource): void {
63 getEnv(self).dispatchMainAction({
64 action: 'set-theme-source',
65 themeSource,
66 });
67 },
68 toggleDarkMode(): void {
69 if (self.shared.shouldUseDarkColors) {
70 this.setThemeSource('light');
71 } else {
72 this.setThemeSource('dark');
73 }
74 },
75 setShowLocationBar(showLocationBar: boolean): void {
76 getEnv(self).dispatchMainAction({
77 action: 'set-show-location-bar',
78 showLocationBar,
79 });
80 },
81 toggleLocationBar(): void {
82 this.setShowLocationBar(!self.settings.showLocationBar);
83 },
84 })); 53 }));
85 54
86/* 55/*
diff --git a/packages/renderer/src/stores/Service.ts b/packages/renderer/src/stores/Service.ts
new file mode 100644
index 0000000..c2c938a
--- /dev/null
+++ b/packages/renderer/src/stores/Service.ts
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { defineServiceModel } from '@sophie/shared';
22import { Instance } from 'mobx-state-tree';
23
24import ServiceSettings from './ServiceSettings';
25
26const Service = defineServiceModel(ServiceSettings);
27
28/*
29 eslint-disable-next-line @typescript-eslint/no-redeclare --
30 Intentionally naming the type the same as the store definition.
31*/
32interface Service extends Instance<typeof Service> {}
33
34export default Service;
diff --git a/packages/shared/src/stores/ServiceSettings.ts b/packages/renderer/src/stores/ServiceSettings.ts
index a5811f5..5d37347 100644
--- a/packages/shared/src/stores/ServiceSettings.ts
+++ b/packages/renderer/src/stores/ServiceSettings.ts
@@ -18,17 +18,12 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { Instance, types, SnapshotIn, SnapshotOut } from 'mobx-state-tree'; 21import { defineServiceSettingsModel } from '@sophie/shared';
22import { Instance } from 'mobx-state-tree';
22 23
23import Profile from './Profile'; 24import Profile from './Profile';
24 25
25const ServiceSettings = /* @__PURE__ */ (() => 26const ServiceSettings = defineServiceSettingsModel(Profile);
26 types.model('ServiceSettings', {
27 name: types.string,
28 profile: types.reference(Profile),
29 // TODO: Remove this once recipes are added.
30 url: types.string,
31 }))();
32 27
33/* 28/*
34 eslint-disable-next-line @typescript-eslint/no-redeclare -- 29 eslint-disable-next-line @typescript-eslint/no-redeclare --
@@ -38,8 +33,7 @@ interface ServiceSettings extends Instance<typeof ServiceSettings> {}
38 33
39export default ServiceSettings; 34export default ServiceSettings;
40 35
41export interface ServiceSettingsSnapshotIn 36export type {
42 extends SnapshotIn<typeof ServiceSettings> {} 37 ServiceSettingsSnapshotIn,
43 38 ServiceSettingsSnapshotOut,
44export interface ServiceSettingsSnapshotOut 39} from '@sophie/shared';
45 extends SnapshotOut<typeof ServiceSettings> {}
diff --git a/packages/shared/src/stores/SharedStore.ts b/packages/renderer/src/stores/SharedStore.ts
index d81a3d3..062479d 100644
--- a/packages/shared/src/stores/SharedStore.ts
+++ b/packages/renderer/src/stores/SharedStore.ts
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com> 2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 * 3 *
4 * This file is part of Sophie. 4 * This file is part of Sophie.
5 * 5 *
@@ -18,27 +18,26 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { 21import { defineSharedStoreModel } from '@sophie/shared';
22 IJsonPatch, 22import { Instance } from 'mobx-state-tree';
23 Instance,
24 types,
25 SnapshotIn,
26 SnapshotOut,
27} from 'mobx-state-tree';
28 23
29import GlobalSettings from './GlobalSettings'; 24import GlobalSettings from './GlobalSettings';
30import Profile from './Profile'; 25import Profile from './Profile';
31import Service from './Service'; 26import Service from './Service';
32 27
33const SharedStore = /* @__PURE__ */ (() => 28const SharedStore = defineSharedStoreModel(
34 types.model('SharedStore', { 29 GlobalSettings,
35 settings: types.optional(GlobalSettings, {}), 30 Profile,
36 profilesById: types.map(Profile), 31 Service,
37 profiles: types.array(types.reference(Profile)), 32).actions((self) => ({
38 servicesById: types.map(Service), 33 toggleDarkMode(): void {
39 services: types.array(types.reference(Service)), 34 if (self.shouldUseDarkColors) {
40 shouldUseDarkColors: false, 35 self.settings.setThemeSource('light');
41 }))(); 36 } else {
37 self.settings.setThemeSource('dark');
38 }
39 },
40}));
42 41
43/* 42/*
44 eslint-disable-next-line @typescript-eslint/no-redeclare -- 43 eslint-disable-next-line @typescript-eslint/no-redeclare --
@@ -48,13 +47,7 @@ interface SharedStore extends Instance<typeof SharedStore> {}
48 47
49export default SharedStore; 48export default SharedStore;
50 49
51export interface SharedStoreSnapshotIn extends SnapshotIn<typeof SharedStore> {} 50export type {
52 51 SharedStoreSnapshotIn,
53export interface SharedStoreSnapshotOut 52 SharedStoreSnapshotOut,
54 extends SnapshotOut<typeof SharedStore> {} 53} from '@sophie/shared';
55
56export interface SharedStoreListener {
57 onSnapshot(snapshot: SharedStoreSnapshotIn): void;
58
59 onPatch(patches: IJsonPatch[]): void;
60}
diff --git a/packages/shared/src/contextBridge/SophieRenderer.ts b/packages/shared/src/contextBridge/SophieRenderer.ts
index 28dc0b7..9e087da 100644
--- a/packages/shared/src/contextBridge/SophieRenderer.ts
+++ b/packages/shared/src/contextBridge/SophieRenderer.ts
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21import { Action } from '../schemas'; 21import { Action } from '../schemas';
22import { SharedStoreListener } from '../stores/SharedStore'; 22import { SharedStoreListener } from '../stores/SharedStoreBase';
23 23
24export default interface SophieRenderer { 24export default interface SophieRenderer {
25 onSharedStoreChange(this: void, listener: SharedStoreListener): Promise<void>; 25 onSharedStoreChange(this: void, listener: SharedStoreListener): Promise<void>;
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index 3d30488..66debf7 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -27,8 +27,11 @@ export { Action, BrowserViewBounds, ThemeSource } from './schemas';
27export type { 27export type {
28 GlobalSettingsSnapshotIn, 28 GlobalSettingsSnapshotIn,
29 GlobalSettingsSnapshotOut, 29 GlobalSettingsSnapshotOut,
30} from './stores/GlobalSettings'; 30} from './stores/GlobalSettingsBase';
31export { default as GlobalSettings } from './stores/GlobalSettings'; 31export {
32 default as GlobalSettingsBase,
33 defineGlobalSettingsModel,
34} from './stores/GlobalSettingsBase';
32 35
33export { default as Profile } from './stores/Profile'; 36export { default as Profile } from './stores/Profile';
34 37
@@ -38,17 +41,26 @@ export type {
38} from './stores/ProfileSettings'; 41} from './stores/ProfileSettings';
39export { default as ProfileSettings } from './stores/ProfileSettings'; 42export { default as ProfileSettings } from './stores/ProfileSettings';
40 43
41export { default as Service } from './stores/Service'; 44export {
45 default as ServiceBase,
46 defineServiceModel,
47} from './stores/ServiceBase';
42 48
43export type { 49export type {
44 ServiceSettingsSnapshotIn, 50 ServiceSettingsSnapshotIn,
45 ServiceSettingsSnapshotOut, 51 ServiceSettingsSnapshotOut,
46} from './stores/ServiceSettings'; 52} from './stores/ServiceSettingsBase';
47export { default as ServiceSettings } from './stores/ServiceSettings'; 53export {
54 default as ServiceSettingsBase,
55 defineServiceSettingsModel,
56} from './stores/ServiceSettingsBase';
48 57
49export type { 58export type {
50 SharedStoreListener, 59 SharedStoreListener,
51 SharedStoreSnapshotIn, 60 SharedStoreSnapshotIn,
52 SharedStoreSnapshotOut, 61 SharedStoreSnapshotOut,
53} from './stores/SharedStore'; 62} from './stores/SharedStoreBase';
54export { default as SharedStore } from './stores/SharedStore'; 63export {
64 default as SharedStoreBase,
65 defineSharedStoreModel,
66} from './stores/SharedStoreBase';
diff --git a/packages/shared/src/stores/GlobalSettings.ts b/packages/shared/src/stores/GlobalSettingsBase.ts
index f316af9..48092fd 100644
--- a/packages/shared/src/stores/GlobalSettings.ts
+++ b/packages/shared/src/stores/GlobalSettingsBase.ts
@@ -18,32 +18,44 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { Instance, types, SnapshotIn, SnapshotOut } from 'mobx-state-tree'; 21import {
22 Instance,
23 types,
24 SnapshotIn,
25 SnapshotOut,
26 IAnyModelType,
27} from 'mobx-state-tree';
22 28
23import { ThemeSource } from '../schemas'; 29import { ThemeSource } from '../schemas';
24 30
25import Service from './Service'; 31import ServiceBase from './ServiceBase';
26 32
27const GlobalSettings = /* @__PURE__ */ (() => 33export function defineGlobalSettingsModel<TS extends IAnyModelType>(
28 types.model('GlobalSettings', { 34 service: TS,
35) {
36 return types.model('GlobalSettings', {
29 themeSource: types.optional( 37 themeSource: types.optional(
30 types.enumeration(ThemeSource.options), 38 types.enumeration(ThemeSource.options),
31 'system', 39 'system',
32 ), 40 ),
33 showLocationBar: false, 41 showLocationBar: false,
34 selectedService: types.safeReference(Service), 42 selectedService: types.safeReference(service),
35 }))(); 43 });
44}
45
46const GlobalSettingsBase = /* @__PURE__ */ (() =>
47 defineGlobalSettingsModel(ServiceBase))();
36 48
37/* 49/*
38 eslint-disable-next-line @typescript-eslint/no-redeclare -- 50 eslint-disable-next-line @typescript-eslint/no-redeclare --
39 Intentionally naming the type the same as the store definition. 51 Intentionally naming the type the same as the store definition.
40*/ 52*/
41interface GlobalSettings extends Instance<typeof GlobalSettings> {} 53interface GlobalSettingsBase extends Instance<typeof GlobalSettingsBase> {}
42 54
43export default GlobalSettings; 55export default GlobalSettingsBase;
44 56
45export interface GlobalSettingsSnapshotIn 57export interface GlobalSettingsSnapshotIn
46 extends SnapshotIn<typeof GlobalSettings> {} 58 extends SnapshotIn<typeof GlobalSettingsBase> {}
47 59
48export interface GlobalSettingsSnapshotOut 60export interface GlobalSettingsSnapshotOut
49 extends SnapshotOut<typeof GlobalSettings> {} 61 extends SnapshotOut<typeof GlobalSettingsBase> {}
diff --git a/packages/shared/src/stores/Service.ts b/packages/shared/src/stores/ServiceBase.ts
index a4e3c92..cde403b 100644
--- a/packages/shared/src/stores/Service.ts
+++ b/packages/shared/src/stores/ServiceBase.ts
@@ -18,14 +18,14 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { Instance, types } from 'mobx-state-tree'; 21import { IAnyModelType, Instance, types } from 'mobx-state-tree';
22 22
23import ServiceSettings from './ServiceSettings'; 23import ServiceSettingsBase from './ServiceSettingsBase';
24 24
25const Service = /* @__PURE__ */ (() => 25export function defineServiceModel<TS extends IAnyModelType>(settings: TS) {
26 types.model('Service', { 26 return types.model('Service', {
27 id: types.identifier, 27 id: types.identifier,
28 settings: ServiceSettings, 28 settings,
29 currentUrl: types.maybe(types.string), 29 currentUrl: types.maybe(types.string),
30 canGoBack: false, 30 canGoBack: false,
31 canGoForward: false, 31 canGoForward: false,
@@ -36,12 +36,16 @@ const Service = /* @__PURE__ */ (() =>
36 ), 36 ),
37 directMessageCount: 0, 37 directMessageCount: 0,
38 indirectMessageCount: 0, 38 indirectMessageCount: 0,
39 }))(); 39 });
40}
41
42const ServiceBase = /* @__PURE__ */ (() =>
43 defineServiceModel(ServiceSettingsBase))();
40 44
41/* 45/*
42 eslint-disable-next-line @typescript-eslint/no-redeclare -- 46 eslint-disable-next-line @typescript-eslint/no-redeclare --
43 Intentionally naming the type the same as the store definition. 47 Intentionally naming the type the same as the store definition.
44*/ 48*/
45interface Service extends Instance<typeof Service> {} 49interface ServiceBase extends Instance<typeof ServiceBase> {}
46 50
47export default Service; 51export default ServiceBase;
diff --git a/packages/shared/src/stores/ServiceSettingsBase.ts b/packages/shared/src/stores/ServiceSettingsBase.ts
new file mode 100644
index 0000000..45eb15d
--- /dev/null
+++ b/packages/shared/src/stores/ServiceSettingsBase.ts
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import {
22 Instance,
23 types,
24 SnapshotIn,
25 SnapshotOut,
26 IAnyModelType,
27} from 'mobx-state-tree';
28
29import ProfileBase from './Profile';
30
31export function defineServiceSettingsModel<TP extends IAnyModelType>(
32 profile: TP,
33) {
34 return types.model('ServiceSettings', {
35 name: types.string,
36 profile: types.reference(profile),
37 // TODO: Remove this once recipes are added.
38 url: types.string,
39 });
40}
41
42const ServiceSettingsBase = /* @__PURE__ */ (() =>
43 defineServiceSettingsModel(ProfileBase))();
44
45/*
46 eslint-disable-next-line @typescript-eslint/no-redeclare --
47 Intentionally naming the type the same as the store definition.
48*/
49interface ServiceSettingsBase extends Instance<typeof ServiceSettingsBase> {}
50
51export default ServiceSettingsBase;
52
53export interface ServiceSettingsSnapshotIn
54 extends SnapshotIn<typeof ServiceSettingsBase> {}
55
56export interface ServiceSettingsSnapshotOut
57 extends SnapshotOut<typeof ServiceSettingsBase> {}
diff --git a/packages/shared/src/stores/SharedStoreBase.ts b/packages/shared/src/stores/SharedStoreBase.ts
new file mode 100644
index 0000000..8d6624b
--- /dev/null
+++ b/packages/shared/src/stores/SharedStoreBase.ts
@@ -0,0 +1,70 @@
1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import {
22 IJsonPatch,
23 Instance,
24 types,
25 SnapshotIn,
26 SnapshotOut,
27 IAnyModelType,
28} from 'mobx-state-tree';
29
30import GlobalSettingsBase from './GlobalSettingsBase';
31import ProfileBase from './Profile';
32import ServiceBase from './ServiceBase';
33
34export function defineSharedStoreModel<
35 TG extends IAnyModelType,
36 TP extends IAnyModelType,
37 TS extends IAnyModelType,
38>(globalSettings: TG, profile: TP, service: TS) {
39 return types.model('SharedStore', {
40 settings: types.optional(globalSettings, {}),
41 profilesById: types.map(profile),
42 profiles: types.array(types.reference(profile)),
43 servicesById: types.map(service),
44 services: types.array(types.reference(service)),
45 shouldUseDarkColors: false,
46 });
47}
48
49const SharedStoreBase = /* @__PURE__ */ (() =>
50 defineSharedStoreModel(GlobalSettingsBase, ProfileBase, ServiceBase))();
51
52/*
53 eslint-disable-next-line @typescript-eslint/no-redeclare --
54 Intentionally naming the type the same as the store definition.
55*/
56interface SharedStoreBase extends Instance<typeof SharedStoreBase> {}
57
58export default SharedStoreBase;
59
60export interface SharedStoreSnapshotIn
61 extends SnapshotIn<typeof SharedStoreBase> {}
62
63export interface SharedStoreSnapshotOut
64 extends SnapshotOut<typeof SharedStoreBase> {}
65
66export interface SharedStoreListener {
67 onSnapshot(snapshot: SharedStoreSnapshotIn): void;
68
69 onPatch(patches: IJsonPatch[]): void;
70}