/* * Copyright (C) 2021-2022 Kristóf Marussy * * This file is part of Sophie. * * Sophie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * SPDX-License-Identifier: AGPL-3.0-only */ import { defineSharedStoreModel, WritingDirection } from '@sophie/shared'; import { getSnapshot, Instance } from 'mobx-state-tree'; import { getLogger } from '../utils/log'; import GlobalSettings from './GlobalSettings'; import Profile from './Profile'; import Service from './Service'; import type Config from './config/Config'; import loadConfig from './config/loadConfig'; const log = getLogger('SharedStore'); function getConfigs(models: { config: T }[]): T[] | undefined { return models.length === 0 ? undefined : models.map((model) => model.config); } const SharedStore = defineSharedStoreModel(GlobalSettings, Profile, Service) .views((self) => ({ get config(): Config { const { settings, profiles, services } = self; const globalSettingsConfig = getSnapshot(settings); return { ...globalSettingsConfig, profiles: getConfigs(profiles), services: getConfigs(services), }; }, get canSwitchServices(): boolean { return self.services.length >= 2; }, get selectedServiceIndex(): number { const { services, settings: { selectedService }, } = self; if (selectedService === undefined) { return -1; } return services.indexOf(selectedService); }, })) .actions((self) => ({ loadConfig(config: Config): void { loadConfig(self, config); }, setLanguage(langauge: string, writingDirection: WritingDirection): void { self.language = langauge; self.writingDirection = writingDirection; }, setShouldUseDarkColors(shouldUseDarkColors: boolean): void { self.shouldUseDarkColors = shouldUseDarkColors; }, activateServiceByOffset(offset: number): void { if (offset === 0) { return; } const { selectedServiceIndex: index, services, settings } = self; if (index < 0) { log.warn('No selected service to offset'); return; } const { length } = services; const indexWithOffset = (index + offset) % length; // Make sure that `newIndex` is positive even for large negative `offset`. const newIndex = indexWithOffset < 0 ? indexWithOffset + length : indexWithOffset; const newService = services.at(newIndex); if (newService === undefined) { log.error( 'Could not advance selected service index from', index, 'by', offset, 'to', newIndex, ); return; } settings.setSelectedService(newService); }, })) .actions((self) => ({ activateNextService(): void { self.activateServiceByOffset(1); }, activatePreviousService(): void { self.activateServiceByOffset(-1); }, })); /* eslint-disable-next-line @typescript-eslint/no-redeclare -- Intentionally naming the type the same as the store definition. */ interface SharedStore extends Instance {} export default SharedStore; export type { SharedStoreSnapshotIn, SharedStoreSnapshotOut, } from '@sophie/shared';