/* * Copyright (C) 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 type { UnreadCount } from '@sophie/service-shared'; import { defineServiceModel, ServiceAction } from '@sophie/shared'; import { Instance, getSnapshot } from 'mobx-state-tree'; import type { ServiceView } from '../infrastructure/electron/types'; import { getLogger } from '../utils/log'; import ServiceSettings from './ServiceSettings'; import type ServiceConfig from './config/ServiceConfig'; const log = getLogger('Service'); const Service = defineServiceModel(ServiceSettings) .views((self) => ({ get config(): ServiceConfig { const { id, settings } = self; return { ...getSnapshot(settings), id }; }, get urlToLoad(): string { return self.currentUrl ?? self.settings.url; }, get shouldBeLoaded(): boolean { return self.state !== 'crashed'; }, })) .volatile( (): { serviceView: ServiceView | undefined; } => ({ serviceView: undefined, }), ) .actions((self) => ({ setLocation({ url, canGoBack, canGoForward, }: { url: string; canGoBack: boolean; canGoForward: boolean; }): void { self.currentUrl = url; self.canGoBack = canGoBack; self.canGoForward = canGoForward; }, setTitle(title: string): void { self.title = title; }, startedLoading(): void { self.state = 'loading'; }, finishedLoading(): void { if (self.state === 'loading') { // Do not overwrite crashed state if the service haven't been reloaded yet. self.state = 'loaded'; } }, crashed(): void { self.state = 'crashed'; }, setUnreadCount({ direct, indirect }: UnreadCount): void { if (direct !== undefined) { self.directMessageCount = direct; } if (indirect !== undefined) { self.indirectMessageCount = indirect; } }, setServiceView(serviceView: ServiceView | undefined): void { self.serviceView = serviceView; }, goBack(): void { self.serviceView?.goBack(); }, goForward(): void { self.serviceView?.goForward(); }, reload(ignoreCache = false): void { if (self.serviceView === undefined) { this.startedLoading(); } else { self.serviceView?.reload(ignoreCache); } }, stop(): void { self.serviceView?.stop(); }, go(url: string): void { if (self.serviceView === undefined) { self.currentUrl = url; this.startedLoading(); } else { self.serviceView?.loadURL(url).catch((error) => { log.warn('Error while loading', url, error); this.crashed(); }); } }, goHome(): void { this.go(self.settings.url); }, dispatch(action: ServiceAction): void { switch (action.action) { case 'back': this.goBack(); break; case 'forward': this.goForward(); break; case 'reload': this.reload(action.ignoreCache); break; case 'stop': this.stop(); break; case 'go-home': this.goHome(); break; case 'go': this.go(action.url); break; default: log.error('Unknown action to dispatch', action); break; } }, })); /* eslint-disable-next-line @typescript-eslint/no-redeclare -- Intentionally naming the type the same as the store definition. */ interface Service extends Instance {} export default Service;