Skip to content

Commit

Permalink
feat(gui): implement settings import/export system
Browse files Browse the repository at this point in the history
  • Loading branch information
SARDONYX-sard committed Feb 7, 2024
1 parent 50b0570 commit 7ada442
Show file tree
Hide file tree
Showing 18 changed files with 444 additions and 280 deletions.
75 changes: 75 additions & 0 deletions frontend/src/components/buttons/backup_btn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { FileOpen } from '@mui/icons-material';
import { Button, type ButtonProps, Tooltip } from '@mui/material';
import { type ReactNode } from 'react';

import { notify } from '@/components/notifications';
import { useTranslation } from '@/hooks';
import { backup } from '@/tauri_cmd';

type Props = {
buttonName: ReactNode;
tooltipTitle: ReactNode;
} & ButtonProps;

export const BackupButton = ({ buttonName, tooltipTitle, ...props }: Readonly<Props>) => (
<Tooltip title={tooltipTitle}>
<Button
sx={{
height: '4em',
marginBottom: '8px',
marginRight: '8px',
marginTop: '8px',
minWidth: '120px',
width: '120px',
}}
startIcon={<FileOpen />}
type="button"
variant="outlined"
{...props}
>
{buttonName}
</Button>
</Tooltip>
);

export const ImportBackupButton = () => {
const { t } = useTranslation();

const handleClick = async () => {
try {
await backup.import();
} catch (e) {
notify.error(`${e}`);
}
};

return (
<BackupButton
buttonName={t('backup-import-btn-name')}
tooltipTitle={t('backup-import-tooltip')}
onClick={handleClick}
/>
);
};

export const ExportBackupButton = () => {
const { t } = useTranslation();

const handleClick = async () => {
try {
if (await backup.export()) {
notify.success(t('backup-export-success'));
}
} catch (e) {
notify.error(`${e}`);
}
};

return (
<BackupButton
buttonName={t('backup-export-btn-name')}
tooltipTitle={t('backup-export-tooltip')}
onClick={handleClick}
/>
);
};
4 changes: 2 additions & 2 deletions frontend/src/components/buttons/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @index('./*', f => `export * from '${f.path}'`)
export * from './backup_btn';
export * from './convert_btn';
export * from './import_lang_btn';
export * from './log_dir_btn';
export * from './log_file_btn';
export * from './log_btn';
export * from './path_selector';
export * from './remove_oar_btn';
export * from './unhide_dar_btn';
70 changes: 70 additions & 0 deletions frontend/src/components/buttons/log_btn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { FileOpen } from '@mui/icons-material';
import FolderOpenIcon from '@mui/icons-material/FolderOpen';
import { Button, type ButtonProps, Tooltip } from '@mui/material';
import { type ReactNode } from 'react';

import { notify } from '@/components/notifications';
import { useTranslation } from '@/hooks';
import { openLogDir, openLogFile } from '@/tauri_cmd';

type Props = {
buttonName: ReactNode;
tooltipTitle: ReactNode;
} & ButtonProps;

export const LogButton = ({ buttonName, tooltipTitle, ...props }: Props) => (
<Tooltip title={tooltipTitle}>
<Button
sx={{
marginTop: '9px',
width: '100%',
height: '60%',
}}
startIcon={<FileOpen />}
type="button"
variant="outlined"
{...props}
>
{buttonName}
</Button>
</Tooltip>
);

export const LogFileButton = () => {
const { t } = useTranslation();

const handleClick = async () => {
try {
await openLogFile();
} catch (error) {
if (error instanceof Error) {
notify.error(error.message);
}
}
};

return <LogButton buttonName={t('open-log-btn')} tooltipTitle={t('open-log-tooltip')} onClick={handleClick} />;
};

export const LogDirButton = () => {
const { t } = useTranslation();

const handleClick = async () => {
try {
await openLogDir();
} catch (error) {
if (error instanceof Error) {
notify.error(error.message);
}
}
};

return (
<LogButton
buttonName={t('open-log-dir-btn')}
onClick={handleClick}
startIcon={<FolderOpenIcon />}
tooltipTitle={t('open-log-dir-tooltip')}
/>
);
};
37 changes: 0 additions & 37 deletions frontend/src/components/buttons/log_dir_btn.tsx

This file was deleted.

38 changes: 0 additions & 38 deletions frontend/src/components/buttons/log_file_btn.tsx

This file was deleted.

8 changes: 7 additions & 1 deletion frontend/src/components/notifications/notify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export const getPosition = (): SnackbarOrigin => {
horizontal: 'right',
vertical: 'bottom',
} as const;
const posJson = JSON.parse(localStorage.getItem('snackbar-position') ?? '{}') as Partial<SnackbarOrigin>;

let posJson: Partial<SnackbarOrigin> = defaultPosition;
try {
posJson = JSON.parse(localStorage.getItem('snackbar-position') ?? '{}');
} catch (error) {
console.error(error);
}

return {
horizontal: posJson?.horizontal ?? defaultPosition.horizontal,
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/components/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import InputLabel from '@mui/material/InputLabel';
import Tab from '@mui/material/Tab';
import AceEditor from 'react-ace';

import { ImportLangButton } from '@/components/buttons';
import { ImportBackupButton, ExportBackupButton, ImportLangButton } from '@/components/buttons';
import {
NoticePositionList,
SelectEditorMode,
type SelectEditorProps,
StyleList,
type StyleListProps,
TranslationList,
type SelectEditorProps,
type StyleListProps,
} from '@/components/lists';
import { useDynStyle, useInjectScript, useLocale, useStorageState, useTranslation } from '@/hooks';
import { start } from '@/tauri_cmd';
Expand Down Expand Up @@ -184,6 +184,7 @@ const Tabs = ({ editorMode, setEditorMode, preset, setPreset, setStyle }: TabsPr
<Tab label={t('tab-label-editor')} value="editor" />
<Tab label={t('tab-label-notice')} value="notice" />
<Tab label={t('tab-label-lang')} value="lang" />
<Tab label={t('tab-label-backup')} value="backup" />
</TabList>
</Box>
<TabPanel value="editor">
Expand All @@ -197,6 +198,10 @@ const Tabs = ({ editorMode, setEditorMode, preset, setPreset, setStyle }: TabsPr
<ImportLangButton />
<TranslationList />
</TabPanel>
<TabPanel value="backup">
<ImportBackupButton />
<ExportBackupButton />
</TabPanel>
</TabContext>
</Box>
);
Expand Down
46 changes: 46 additions & 0 deletions frontend/src/tauri_cmd/backup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { save } from '@tauri-apps/api/dialog';
import { writeTextFile } from '@tauri-apps/api/fs';

import { readFile } from '.';

export const backup = {
/** @throws Error */
async import() {
const pathKey = 'import-backup-path';
const settings = await readFile(pathKey, 'g_dar2oar_settings');
if (settings) {
// TODO: This is unsafe because the key is not validated.
const obj = JSON.parse(settings);
Object.keys(obj).forEach((key) => {
// The import path does not need to be overwritten.
if (key === pathKey) {
return;
}
localStorage.setItem(key, obj[key]);
});
window.location.reload(); // To enable
}
},

/** @throws Error */
async export() {
const pathKey = 'export-settings-path';
const path = await save({
defaultPath: localStorage.getItem(pathKey) ?? '',
filters: [
{
name: 'g_dar2oar_settings',
extensions: ['json'],
},
],
});

if (typeof path === 'string') {
localStorage.setItem(pathKey, path);
await writeTextFile(path, JSON.stringify(localStorage));
return path;
} else {
return null;
}
},
};
Loading

0 comments on commit 7ada442

Please sign in to comment.