mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
fix(electron): sync settings from localStorage -> atom -> electron (#5020)
- moved `appSettingAtom` to infra since we now have different packages that depends on it. There is no better place to fit in for now - use atomEffect to sync setting changes to updater related configs to Electron side - refactored how Electron reacts to updater config changes.
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
import { atom } from 'jotai';
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
|
||||
export type DateFormats =
|
||||
| 'MM/dd/YYYY'
|
||||
| 'dd/MM/YYYY'
|
||||
| 'YYYY-MM-dd'
|
||||
| 'YYYY.MM.dd'
|
||||
| 'YYYY/MM/dd'
|
||||
| 'dd-MMM-YYYY'
|
||||
| 'dd MMMM YYYY';
|
||||
|
||||
export type AppSetting = {
|
||||
clientBorder: boolean;
|
||||
fullWidthLayout: boolean;
|
||||
windowFrameStyle: 'frameless' | 'NativeTitleBar';
|
||||
fontStyle: FontFamily;
|
||||
dateFormat: DateFormats;
|
||||
startWeekOnMonday: boolean;
|
||||
enableBlurBackground: boolean;
|
||||
enableNoisyBackground: boolean;
|
||||
autoCheckUpdate: boolean;
|
||||
autoDownloadUpdate: boolean;
|
||||
};
|
||||
export const windowFrameStyleOptions: AppSetting['windowFrameStyle'][] = [
|
||||
'frameless',
|
||||
'NativeTitleBar',
|
||||
];
|
||||
|
||||
export const dateFormatOptions: DateFormats[] = [
|
||||
'MM/dd/YYYY',
|
||||
'dd/MM/YYYY',
|
||||
'YYYY-MM-dd',
|
||||
'YYYY.MM.dd',
|
||||
'YYYY/MM/dd',
|
||||
'dd-MMM-YYYY',
|
||||
'dd MMMM YYYY',
|
||||
];
|
||||
|
||||
export type FontFamily = 'Sans' | 'Serif' | 'Mono';
|
||||
|
||||
export const fontStyleOptions = [
|
||||
{ key: 'Sans', value: 'var(--affine-font-sans-family)' },
|
||||
{ key: 'Serif', value: 'var(--affine-font-serif-family)' },
|
||||
{ key: 'Mono', value: 'var(--affine-font-mono-family)' },
|
||||
] satisfies {
|
||||
key: FontFamily;
|
||||
value: string;
|
||||
}[];
|
||||
|
||||
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
|
||||
clientBorder: environment.isDesktop && !environment.isWindows,
|
||||
fullWidthLayout: false,
|
||||
windowFrameStyle: 'frameless',
|
||||
fontStyle: 'Sans',
|
||||
dateFormat: dateFormatOptions[0],
|
||||
startWeekOnMonday: false,
|
||||
enableBlurBackground: true,
|
||||
enableNoisyBackground: true,
|
||||
autoCheckUpdate: true,
|
||||
autoDownloadUpdate: true,
|
||||
});
|
||||
|
||||
type SetStateAction<Value> = Value | ((prev: Value) => Value);
|
||||
|
||||
export const appSettingAtom = atom<
|
||||
AppSetting,
|
||||
[SetStateAction<Partial<AppSetting>>],
|
||||
void
|
||||
>(
|
||||
get => get(appSettingBaseAtom),
|
||||
(get, set, apply) => {
|
||||
const prev = get(appSettingBaseAtom);
|
||||
const next = typeof apply === 'function' ? apply(prev) : apply;
|
||||
set(appSettingBaseAtom, { ...prev, ...next });
|
||||
}
|
||||
);
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import { appSettingAtom } from '@toeverything/infra/atom';
|
||||
import {
|
||||
PreconditionStrategy,
|
||||
registerAffineCommand,
|
||||
@@ -8,7 +9,6 @@ import { type createStore } from 'jotai';
|
||||
import type { useTheme } from 'next-themes';
|
||||
|
||||
import { openQuickSearchModalAtom } from '../atoms';
|
||||
import { appSettingAtom } from '../atoms/settings';
|
||||
import type { useLanguageHelper } from '../hooks/affine/use-language-helper';
|
||||
|
||||
export function registerAffineSettingsCommands({
|
||||
|
||||
@@ -3,15 +3,8 @@ import { SettingRow } from '@affine/component/setting-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import {
|
||||
downloadProgressAtom,
|
||||
isCheckingForUpdatesAtom,
|
||||
updateAvailableAtom,
|
||||
updateReadyAtom,
|
||||
useAppUpdater,
|
||||
} from '@toeverything/hooks/use-app-updater';
|
||||
import { useAppUpdater } from '@toeverything/hooks/use-app-updater';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import * as styles from './style.css';
|
||||
@@ -25,18 +18,16 @@ enum CheckUpdateStatus {
|
||||
|
||||
const useUpdateStatusLabels = (checkUpdateStatus: CheckUpdateStatus) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const isCheckingForUpdates = useAtomValue(isCheckingForUpdatesAtom);
|
||||
const updateAvailable = useAtomValue(updateAvailableAtom);
|
||||
const updateReady = useAtomValue(updateReadyAtom);
|
||||
const downloadProgress = useAtomValue(downloadProgressAtom);
|
||||
const { updateAvailable, downloadProgress, updateReady, checkingForUpdates } =
|
||||
useAppUpdater();
|
||||
|
||||
const buttonLabel = useMemo(() => {
|
||||
if (updateAvailable && downloadProgress === null) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.button.download']();
|
||||
}
|
||||
if (updateReady) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.button.restart']();
|
||||
}
|
||||
if (updateAvailable && downloadProgress === null) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.button.download']();
|
||||
}
|
||||
if (
|
||||
checkUpdateStatus === CheckUpdateStatus.LATEST ||
|
||||
checkUpdateStatus === CheckUpdateStatus.ERROR
|
||||
@@ -47,16 +38,16 @@ const useUpdateStatusLabels = (checkUpdateStatus: CheckUpdateStatus) => {
|
||||
}, [checkUpdateStatus, downloadProgress, t, updateAvailable, updateReady]);
|
||||
|
||||
const subtitleLabel = useMemo(() => {
|
||||
if (updateAvailable && downloadProgress === null) {
|
||||
if (updateReady) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.restart']();
|
||||
} else if (updateAvailable && downloadProgress === null) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.update-available']({
|
||||
version: updateAvailable.version,
|
||||
});
|
||||
} else if (isCheckingForUpdates) {
|
||||
} else if (checkingForUpdates) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.checking']();
|
||||
} else if (updateAvailable && downloadProgress !== null) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.downloading']();
|
||||
} else if (updateReady) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.restart']();
|
||||
} else if (checkUpdateStatus === CheckUpdateStatus.ERROR) {
|
||||
return t['com.affine.aboutAFFiNE.checkUpdate.subtitle.error']();
|
||||
} else if (checkUpdateStatus === CheckUpdateStatus.LATEST) {
|
||||
@@ -66,7 +57,7 @@ const useUpdateStatusLabels = (checkUpdateStatus: CheckUpdateStatus) => {
|
||||
}, [
|
||||
checkUpdateStatus,
|
||||
downloadProgress,
|
||||
isCheckingForUpdates,
|
||||
checkingForUpdates,
|
||||
t,
|
||||
updateAvailable,
|
||||
updateReady,
|
||||
@@ -83,14 +74,14 @@ const useUpdateStatusLabels = (checkUpdateStatus: CheckUpdateStatus) => {
|
||||
error: checkUpdateStatus === CheckUpdateStatus.ERROR,
|
||||
})}
|
||||
>
|
||||
{isCheckingForUpdates ? <Loading size={14} /> : null}
|
||||
{checkingForUpdates ? <Loading size={14} /> : null}
|
||||
{subtitleLabel}
|
||||
</span>
|
||||
);
|
||||
}, [
|
||||
checkUpdateStatus,
|
||||
downloadProgress,
|
||||
isCheckingForUpdates,
|
||||
checkingForUpdates,
|
||||
subtitleLabel,
|
||||
updateAvailable,
|
||||
updateReady,
|
||||
@@ -101,10 +92,14 @@ const useUpdateStatusLabels = (checkUpdateStatus: CheckUpdateStatus) => {
|
||||
|
||||
export const UpdateCheckSection = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const { checkForUpdates, downloadUpdate, quitAndInstall } = useAppUpdater();
|
||||
const updateAvailable = useAtomValue(updateAvailableAtom);
|
||||
const updateReady = useAtomValue(updateReadyAtom);
|
||||
const downloadProgress = useAtomValue(downloadProgressAtom);
|
||||
const {
|
||||
checkForUpdates,
|
||||
downloadUpdate,
|
||||
quitAndInstall,
|
||||
updateAvailable,
|
||||
downloadProgress,
|
||||
updateReady,
|
||||
} = useAppUpdater();
|
||||
const [checkUpdateStatus, setCheckUpdateStatus] = useState<CheckUpdateStatus>(
|
||||
CheckUpdateStatus.UNCHECK
|
||||
);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu';
|
||||
import { dateFormatOptions, type DateFormats } from '@toeverything/infra/atom';
|
||||
import dayjs from 'dayjs';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
dateFormatOptions,
|
||||
type DateFormats,
|
||||
} from '../../../../../atoms/settings';
|
||||
import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper';
|
||||
|
||||
interface DateFormatMenuContentProps {
|
||||
|
||||
@@ -3,14 +3,14 @@ import { SettingHeader } from '@affine/component/setting-components';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { SettingWrapper } from '@affine/component/setting-components';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
type AppSetting,
|
||||
fontStyleOptions,
|
||||
windowFrameStyleOptions,
|
||||
} from '../../../../../atoms/settings';
|
||||
} from '@toeverything/infra/atom';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper';
|
||||
import { LanguageMenu } from '../../../language-menu';
|
||||
import { DateFormatSetting } from './date-format-setting';
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { pluginEditorAtom } from '@toeverything/infra/__internal__/plugin';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { fontStyleOptions } from '@toeverything/infra/atom';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { CSSProperties } from 'react';
|
||||
@@ -15,7 +16,6 @@ import { memo, Suspense, useCallback, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { type PageMode, pageSettingFamily } from '../atoms';
|
||||
import { fontStyleOptions } from '../atoms/settings';
|
||||
import { useAppSettingHelper } from '../hooks/affine/use-app-setting-helper';
|
||||
import { useBlockSuiteMetaHelper } from '../hooks/affine/use-block-suite-meta-helper';
|
||||
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
||||
|
||||
@@ -20,11 +20,6 @@ import { FolderIcon, SettingsIcon } from '@blocksuite/icons';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import {
|
||||
isAutoCheckUpdateAtom,
|
||||
isAutoDownloadUpdateAtom,
|
||||
useAppUpdater,
|
||||
} from '@toeverything/hooks/use-app-updater';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import type { HTMLAttributes, ReactElement } from 'react';
|
||||
import { forwardRef, useCallback, useEffect, useMemo } from 'react';
|
||||
@@ -107,10 +102,6 @@ export const RootAppSidebar = ({
|
||||
}: RootAppSidebarProps): ReactElement => {
|
||||
const currentWorkspaceId = currentWorkspace.id;
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const { toggleAutoCheck, toggleAutoDownload } = useAppUpdater();
|
||||
const { autoCheckUpdate, autoDownloadUpdate } = appSettings;
|
||||
const isAutoDownload = useAtomValue(isAutoDownloadUpdateAtom);
|
||||
const isAutoCheck = useAtomValue(isAutoCheckUpdateAtom);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
const t = useAFFiNEI18N();
|
||||
const [openUserWorkspaceList, setOpenUserWorkspaceList] = useAtom(
|
||||
@@ -159,26 +150,6 @@ export const RootAppSidebar = ({
|
||||
}
|
||||
}, [sidebarOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!environment.isDesktop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAutoCheck !== autoCheckUpdate) {
|
||||
toggleAutoCheck(autoCheckUpdate);
|
||||
}
|
||||
if (isAutoDownload !== autoDownloadUpdate) {
|
||||
toggleAutoDownload(autoDownloadUpdate);
|
||||
}
|
||||
}, [
|
||||
autoCheckUpdate,
|
||||
autoDownloadUpdate,
|
||||
isAutoCheck,
|
||||
isAutoDownload,
|
||||
toggleAutoCheck,
|
||||
toggleAutoDownload,
|
||||
]);
|
||||
|
||||
const [history, setHistory] = useHistoryAtom();
|
||||
const router = useMemo(() => {
|
||||
return {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { type AppSetting, appSettingAtom } from '@toeverything/infra/atom';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { type AppSetting, appSettingAtom } from '../../atoms/settings';
|
||||
|
||||
export function useAppSettingHelper() {
|
||||
const [appSettings, setAppSettings] = useAtom(appSettingAtom);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { EditorContainer } from '@blocksuite/presets';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import {
|
||||
appSettingAtom,
|
||||
currentPageIdAtom,
|
||||
currentWorkspaceIdAtom,
|
||||
} from '@toeverything/infra/atom';
|
||||
@@ -36,7 +37,6 @@ import type { Map as YMap } from 'yjs';
|
||||
import { setPageModeAtom } from '../../../atoms';
|
||||
import { collectionsCRUDAtom } from '../../../atoms/collections';
|
||||
import { currentModeAtom } from '../../../atoms/mode';
|
||||
import { appSettingAtom } from '../../../atoms/settings';
|
||||
import { AffineErrorBoundary } from '../../../components/affine/affine-error-boundary';
|
||||
import { HubIsland } from '../../../components/affine/hub-island';
|
||||
import { GlobalPageHistoryModal } from '../../../components/affine/page-history-modal';
|
||||
|
||||
Reference in New Issue
Block a user