Move more core logic to new folder
This commit is contained in:
51
src/modules/core/utils/AwaitableDialog.tsx
Normal file
51
src/modules/core/utils/AwaitableDialog.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { ThemeProvider } from '@mui/material/styles';
|
||||
import { ConfirmDialog } from '@/modules/core/components/ConfirmDialog.tsx';
|
||||
import { ControlledPromise } from '@/lib/ControlledPromise.ts';
|
||||
import { getCurrentTheme } from '@/theme.tsx';
|
||||
|
||||
export const awaitConfirmation = async (
|
||||
dialogProps: Omit<React.ComponentProps<typeof ConfirmDialog>, 'onCancel' | 'onConfirm'>,
|
||||
) => {
|
||||
const dialogContainer = document.createElement('div');
|
||||
document.body.appendChild(dialogContainer);
|
||||
|
||||
const root = createRoot(dialogContainer);
|
||||
|
||||
const confirmationPromise = new ControlledPromise();
|
||||
const handleConfirmation = (accepted: boolean) => {
|
||||
if (accepted) {
|
||||
confirmationPromise.resolve();
|
||||
} else {
|
||||
confirmationPromise.reject();
|
||||
}
|
||||
|
||||
root.unmount();
|
||||
document.body.removeChild(dialogContainer);
|
||||
};
|
||||
|
||||
root.render(
|
||||
<ThemeProvider theme={getCurrentTheme()}>
|
||||
<ConfirmDialog
|
||||
{...dialogProps}
|
||||
onExtra={() => {
|
||||
handleConfirmation(false);
|
||||
dialogProps.onExtra?.();
|
||||
}}
|
||||
onCancel={() => handleConfirmation(false)}
|
||||
onConfirm={() => handleConfirmation(true)}
|
||||
/>
|
||||
,
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
return confirmationPromise.promise;
|
||||
};
|
||||
78
src/modules/core/utils/Languages.ts
Normal file
78
src/modules/core/utils/Languages.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { t } from 'i18next';
|
||||
import { ISOLanguage, IsoLanguages } from '@/modules/core/IsoLanguages.ts';
|
||||
|
||||
export enum DefaultLanguage {
|
||||
ALL = 'all',
|
||||
OTHER = 'other',
|
||||
LOCAL_SOURCE = 'localsourcelang',
|
||||
}
|
||||
|
||||
function getISOLanguage(code: string): ISOLanguage | null {
|
||||
if (IsoLanguages[code]) {
|
||||
return IsoLanguages[code];
|
||||
}
|
||||
|
||||
if (IsoLanguages[code.toLocaleLowerCase()]) {
|
||||
return IsoLanguages[code.toLocaleLowerCase()];
|
||||
}
|
||||
|
||||
const whereToCut = code.indexOf('-') !== -1 ? code.indexOf('-') : code.length;
|
||||
const processedCode = code.toLocaleLowerCase().substring(0, whereToCut);
|
||||
if (IsoLanguages[processedCode]) {
|
||||
return IsoLanguages[processedCode];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getLanguage(code: string): { name: string; nativeName: string } {
|
||||
const isoLanguage = getISOLanguage(code);
|
||||
|
||||
if (isoLanguage) {
|
||||
return isoLanguage;
|
||||
}
|
||||
|
||||
return {
|
||||
name: t('global.language.label.language_with_code', { code }),
|
||||
nativeName: t('global.language.label.language_with_code', { code }),
|
||||
};
|
||||
}
|
||||
|
||||
export function langCodeToName(code: string): string {
|
||||
return getLanguage(code).nativeName;
|
||||
}
|
||||
|
||||
function defaultNativeLang() {
|
||||
return 'en'; // TODO: infer from the browser
|
||||
}
|
||||
|
||||
export function extensionDefaultLangs() {
|
||||
return [defaultNativeLang(), DefaultLanguage.ALL];
|
||||
}
|
||||
|
||||
export function sourceDefualtLangs() {
|
||||
return [defaultNativeLang(), DefaultLanguage.LOCAL_SOURCE];
|
||||
}
|
||||
|
||||
export function sourceForcedDefaultLangs(): string[] {
|
||||
return [DefaultLanguage.LOCAL_SOURCE];
|
||||
}
|
||||
|
||||
export const langSortCmp = (a: string, b: string) => {
|
||||
// puts english first for convience
|
||||
const aLang = langCodeToName(a);
|
||||
const bLang = langCodeToName(b);
|
||||
|
||||
if (a === 'en') return -1;
|
||||
if (b === 'en') return 1;
|
||||
|
||||
return aLang.localeCompare(bLang);
|
||||
};
|
||||
74
src/modules/core/utils/MediaQuery.tsx
Normal file
74
src/modules/core/utils/MediaQuery.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { Breakpoint } from '@mui/material/styles';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { getCurrentTheme } from '@/theme.tsx';
|
||||
import { ThemeMode } from '@/modules/theme/contexts/ThemeModeContext.tsx';
|
||||
import { AppStorage } from '@/lib/storage/AppStorage.ts';
|
||||
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
||||
|
||||
export class MediaQuery {
|
||||
static useIsTouchDevice(): boolean {
|
||||
return useMediaQuery('not (pointer: fine)');
|
||||
}
|
||||
|
||||
static useIsBelowWidth(breakpoint: Breakpoint): boolean {
|
||||
return useMediaQuery(getCurrentTheme().breakpoints.down(breakpoint));
|
||||
}
|
||||
|
||||
static useIsMobileWidth(): boolean {
|
||||
return this.useIsBelowWidth('sm');
|
||||
}
|
||||
|
||||
static useGetScrollbarSize(type: 'height' | 'width'): number {
|
||||
const [scrollbarSize, setScrollbarSize] = useState(0);
|
||||
|
||||
useResizeObserver(
|
||||
document.documentElement,
|
||||
useCallback(() => {
|
||||
const height = window.innerHeight - document.documentElement.clientHeight;
|
||||
const width = window.innerWidth - document.documentElement.clientWidth;
|
||||
const size = type === 'height' ? height : width;
|
||||
|
||||
setScrollbarSize(size);
|
||||
}, []),
|
||||
);
|
||||
|
||||
return scrollbarSize;
|
||||
}
|
||||
|
||||
static getSystemThemeMode(): Exclude<ThemeMode, 'system'> {
|
||||
const prefersDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
return prefersDarkMode ? ThemeMode.DARK : ThemeMode.LIGHT;
|
||||
}
|
||||
|
||||
static getThemeMode(): Exclude<ThemeMode, 'system'> {
|
||||
const themeMode = AppStorage.local.getItemParsed<ThemeMode>('themeMode', ThemeMode.SYSTEM);
|
||||
|
||||
const isSystemMode = themeMode === ThemeMode.SYSTEM;
|
||||
if (isSystemMode) {
|
||||
return this.getSystemThemeMode();
|
||||
}
|
||||
|
||||
return themeMode;
|
||||
}
|
||||
|
||||
static listenToSystemThemeChange(onChange: (themeMode: Exclude<ThemeMode, 'system'>) => void): () => void {
|
||||
const handleSystemThemeModeChange = (e: MediaQueryListEvent) => {
|
||||
onChange(e.matches ? ThemeMode.DARK : ThemeMode.LIGHT);
|
||||
};
|
||||
|
||||
const matchSystemThemeMode = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
matchSystemThemeMode.addEventListener('change', handleSystemThemeModeChange);
|
||||
|
||||
return () => matchSystemThemeMode.removeEventListener('change', handleSystemThemeModeChange);
|
||||
}
|
||||
}
|
||||
19
src/modules/core/utils/Toast.ts
Normal file
19
src/modules/core/utils/Toast.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { enqueueSnackbar, OptionsObject, SnackbarKey } from 'notistack';
|
||||
|
||||
export function makeToast(message: string, severity?: OptionsObject['variant']): SnackbarKey;
|
||||
export function makeToast(message: string, options?: OptionsObject): SnackbarKey;
|
||||
export function makeToast(message: string, options: OptionsObject['variant'] | OptionsObject = 'default'): SnackbarKey {
|
||||
if (typeof options === 'string') {
|
||||
return enqueueSnackbar(message, { variant: options });
|
||||
}
|
||||
|
||||
return enqueueSnackbar(message, options);
|
||||
}
|
||||
Reference in New Issue
Block a user