diff --git a/src/common/i18n/languages/en.ts b/src/common/i18n/languages/en.ts index 57f42ab51..e0da619ae 100644 --- a/src/common/i18n/languages/en.ts +++ b/src/common/i18n/languages/en.ts @@ -13,6 +13,7 @@ export default { auto_refresh: 'Auto refresh', btn_cancel: 'Cancel', btn_ok: 'OK', + change: 'Change', check_update: 'Check update', choice_mode: 'Choice mode', choice_mode_default: 'Default', @@ -99,6 +100,8 @@ export default { move_items_to_trashcan: 'Move {0} items to trashcan', move_to_trashcan: 'Move to trashcan', need_to_relaunch: 'Need to relaunch', + need_to_relaunch_after_setting_changed: + 'The setting has been changed and will take effect after the app is restarted.', never: 'Never', new: 'New', new_version_found: 'New version found', @@ -125,6 +128,9 @@ export default { replace: 'Replace', replace_all: 'Replace all', replace_history: 'Replace history', + reset: 'Reset', + reset_data_dir_confirm: + 'Are you sure you want to restore the data folder to the default address ({0})?', reset_zoom: 'Reset zoom', search: 'Search', select_all: 'Select all', diff --git a/src/common/i18n/languages/fr.ts b/src/common/i18n/languages/fr.ts index 9704e2db0..6437f6d9b 100644 --- a/src/common/i18n/languages/fr.ts +++ b/src/common/i18n/languages/fr.ts @@ -13,6 +13,7 @@ export default { auto_refresh: 'Rafraîchissement automatique', btn_cancel: 'Annuler', btn_ok: 'OK', + change: 'Changer', check_update: 'Vérifier les mises à jour', choice_mode: 'Choice mode', choice_mode_default: 'Défaut', @@ -99,6 +100,8 @@ export default { move_items_to_trashcan: 'Déplacer {0} éléments dans la corbeille', move_to_trashcan: 'Déplacer dans la corbeille', need_to_relaunch: 'Besoin de redémarrer', + need_to_relaunch_after_setting_changed: + "Le paramètre a été modifié et prendra effet après le redémarrage de l'application.", never: 'Jamais', new: 'Nouveau', new_version_found: 'Nouvelle version trouvée', @@ -125,6 +128,9 @@ export default { replace: 'Remplacer', replace_all: 'Tout remplacer', replace_history: "Remplacer l'historique", + reset: 'Réinitialiser', + reset_data_dir_confirm: + "Êtes-vous sûr de vouloir réinitialiser le dossier de données à l'adresse par défaut?({0})?", reset_zoom: 'Réinitialiser le zoom', search: 'Rechercher', select_all: 'Tout sélectionner', diff --git a/src/common/i18n/languages/zh.ts b/src/common/i18n/languages/zh.ts index 56d9fbcb7..904ddee91 100644 --- a/src/common/i18n/languages/zh.ts +++ b/src/common/i18n/languages/zh.ts @@ -15,6 +15,7 @@ const lang: LanguageDict = { auto_refresh: '自动刷新', btn_cancel: '取消', btn_ok: '确定', + change: '更改', check_update: '检查更新', choice_mode: '选择模式', choice_mode_default: '默认', @@ -98,6 +99,7 @@ const lang: LanguageDict = { move_items_to_trashcan: '移动 {0} 项到回收站', move_to_trashcan: '移到回收站', need_to_relaunch: '需要重启', + need_to_relaunch_after_setting_changed: '设置已更改,应用重启后生效。', never: '从不', new: '新建', new_version_found: '发现新版本', @@ -124,6 +126,8 @@ const lang: LanguageDict = { replace: '替换', replace_all: '替换所有', replace_history: '替换历史', + reset: '重置', + reset_data_dir_confirm: '确定要把数据文件夹重置为默认地址吗?({0})?', reset_zoom: '重置缩放', search: '搜索', select_all: '全选', diff --git a/src/main/actions/cmd/changeDataDir.ts b/src/main/actions/cmd/changeDataDir.ts new file mode 100644 index 000000000..70cbb9a94 --- /dev/null +++ b/src/main/actions/cmd/changeDataDir.ts @@ -0,0 +1,68 @@ +/** + * @author: oldj + * @homepage: https://oldj.net + */ + +import { + app, + BrowserWindow, + dialog, + OpenDialogOptions, + OpenDialogReturnValue, +} from 'electron' +import { localdb } from '@main/data' +import getDataFolder, { getDefaultDataDir } from '@main/libs/getDataDir' +import getI18N from '@main/core/getI18N' +import { IActionFunc } from '@root/main/types' + +export default async function ( + this: IActionFunc, + to_default?: boolean, +): Promise { + let { sender } = this + let { lang } = await getI18N() + let current_dir = getDataFolder() + let dir: string = '' + + if (to_default) { + dir = getDefaultDataDir() + } else { + let parent = BrowserWindow.fromWebContents(sender) + if (parent?.isFullScreen()) { + parent?.setFullScreen(false) + } + + let options: OpenDialogOptions = { + // title: '选择数据目录', + defaultPath: current_dir, + properties: ['openDirectory', 'createDirectory'], + } + + let r: OpenDialogReturnValue + + if (parent) { + r = await dialog.showOpenDialog(parent, options) + } else { + r = await dialog.showOpenDialog(options) + } + + if (r.canceled) { + return + } + + dir = r.filePaths[0] + } + + if (!dir || dir === current_dir) { + return + } + + await localdb.dict.local.set('data_dir', dir) + dialog.showMessageBoxSync({ + message: lang.need_to_relaunch_after_setting_changed, + }) + app.relaunch() + app.exit(0) + + return dir +} diff --git a/src/main/actions/getDataDir.ts b/src/main/actions/getDataDir.ts new file mode 100644 index 000000000..72b8b01d5 --- /dev/null +++ b/src/main/actions/getDataDir.ts @@ -0,0 +1,8 @@ +/** + * @author: oldj + * @homepage: https://oldj.net + */ + +import getDataDir from '@main/libs/getDataDir' + +export default async () => getDataDir() diff --git a/src/main/actions/getDataFolder.ts b/src/main/actions/getDataFolder.ts deleted file mode 100644 index 1a9687c3b..000000000 --- a/src/main/actions/getDataFolder.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @author: oldj - * @homepage: https://oldj.net - */ - -import getDataFolder from '@main/libs/getDataFolder' - -export default async () => getDataFolder() diff --git a/src/main/actions/getDefaultDataDir.ts b/src/main/actions/getDefaultDataDir.ts new file mode 100644 index 000000000..7b29aec13 --- /dev/null +++ b/src/main/actions/getDefaultDataDir.ts @@ -0,0 +1,8 @@ +/** + * @author: oldj + * @homepage: https://oldj.net + */ + +import { getDefaultDataDir } from '@main/libs/getDataDir' + +export default async () => getDefaultDataDir() diff --git a/src/main/actions/index.ts b/src/main/actions/index.ts index 948556aa2..6ada6d217 100644 --- a/src/main/actions/index.ts +++ b/src/main/actions/index.ts @@ -6,8 +6,9 @@ export { default as ping } from './ping' -export { default as getDataFolder } from './getDataFolder' export { default as getBasicData } from './getBasicData' +export { default as getDataDir } from './getDataDir' +export { default as getDefaultDataDir } from './getDefaultDataDir' export { default as configGet } from './config/get' export { default as configSet } from './config/set' @@ -40,6 +41,7 @@ export { default as cmdDeleteHistory } from './cmd/deleteHistory' export { default as cmdClearHistory } from './cmd/clearHistory' export { default as cmdFocusMainWindow } from './cmd/focusMainWindow' export { default as cmdToggleDevTools } from './cmd/toggleDevTools' +export { default as cmdChangeDataDir } from './cmd/changeDataDir' export { default as openUrl } from './openUrl' export { default as showItemInFolder } from './showItemInFolder' diff --git a/src/main/actions/migrate/checkIfMigration.ts b/src/main/actions/migrate/checkIfMigration.ts index e8013ee19..aabe7e669 100644 --- a/src/main/actions/migrate/checkIfMigration.ts +++ b/src/main/actions/migrate/checkIfMigration.ts @@ -5,7 +5,7 @@ * @homepage: https://oldj.net */ -import getDataFolder from '@main/libs/getDataFolder' +import getDataFolder from '@main/libs/getDataDir' import { isDir } from '@main/utils/fs2' import * as fs from 'fs' import * as path from 'path' diff --git a/src/main/actions/migrate/migrateData.ts b/src/main/actions/migrate/migrateData.ts index f474e84da..8056e29f6 100644 --- a/src/main/actions/migrate/migrateData.ts +++ b/src/main/actions/migrate/migrateData.ts @@ -7,7 +7,7 @@ // migrate data from v3 to v4 import importV3Data from '@main/actions/migrate/importV3Data' -import getDataFolder from '@main/libs/getDataFolder' +import getDataFolder from '@main/libs/getDataDir' import { IHostsBasicData, VersionType } from '@root/common/data' import { cleanHostsList } from '@root/common/hostsFn' import version from '@root/version.json' diff --git a/src/main/core/message.ts b/src/main/core/message.ts index 93529d66d..cd0172c03 100644 --- a/src/main/core/message.ts +++ b/src/main/core/message.ts @@ -5,7 +5,7 @@ */ import * as actions from '@main/actions' -import { ActionData } from '@main/types' +import { ActionData, IActionFunc } from '@main/types' import { ipcMain } from 'electron' import { EventEmitter } from 'events' @@ -79,8 +79,9 @@ ipcMain.on('x_action', async (e, action_data: ActionData) => { } try { + let obj: IActionFunc = { sender } // @ts-ignore - let v = await fn(...params) + let v = await fn.call(obj, ...params) sendBack(sender, callback, [null, v]) } catch (e) { console.error(e) diff --git a/src/main/data/index.ts b/src/main/data/index.ts index e7a90449b..5ca0955e0 100644 --- a/src/main/data/index.ts +++ b/src/main/data/index.ts @@ -4,26 +4,27 @@ * @homepage: https://oldj.net */ -import getDataFolder from '@main/libs/getDataFolder' -import { app } from 'electron' import * as path from 'path' import PotDb from 'potdb' +import { app } from 'electron' +import getDataFolder from '@main/libs/getDataDir' +import getConfigFolder from '@main/libs/getConfigDir' -let swhdb: PotDb -let cfgdb: PotDb let localdb: PotDb +let cfgdb: PotDb +let swhdb: PotDb -if (!global.swhdb) { - let db_dir: string = path.join(getDataFolder(), 'data') - swhdb = new PotDb(db_dir) - console.log(`data db: ${swhdb.dir}`) - global.swhdb = swhdb +if (!global.localdb) { + let db_dir: string = path.join(app.getPath('userData'), 'swh_local') + localdb = new PotDb(db_dir) + console.log(`local db: ${localdb.dir}`) + global.localdb = localdb } else { - swhdb = global.swhdb + localdb = global.localdb } if (!global.cfgdb) { - let db_dir: string = path.join(getDataFolder(), 'config') + let db_dir: string = path.join(getConfigFolder(), 'config') cfgdb = new PotDb(db_dir) console.log(`config db: ${cfgdb.dir}`) global.cfgdb = cfgdb @@ -31,13 +32,16 @@ if (!global.cfgdb) { cfgdb = global.cfgdb } -if (!global.localdb) { - let db_dir: string = path.join(app.getPath('userData'), 'swh_local') - localdb = new PotDb(db_dir) - console.log(`local db: ${localdb.dir}`) - global.localdb = localdb -} else { - localdb = global.localdb +async function getSwhDb(): Promise { + if (!swhdb) { + global.data_dir = await localdb.dict.local.get('data_dir') + let db_dir: string = path.join(getDataFolder(), 'data') + swhdb = new PotDb(db_dir) + console.log(`data db: ${swhdb.dir}`) + global.swhdb = swhdb + } + + return swhdb } -export { swhdb, cfgdb, localdb } +export { localdb, cfgdb, swhdb, getSwhDb } diff --git a/src/main/libs/getDataFolder.ts b/src/main/libs/getConfigDir.ts similarity index 77% rename from src/main/libs/getDataFolder.ts rename to src/main/libs/getConfigDir.ts index 9fc3d17ea..69d45b0db 100644 --- a/src/main/libs/getDataFolder.ts +++ b/src/main/libs/getConfigDir.ts @@ -9,5 +9,5 @@ import { homedir } from 'os' export default (): string => { // todo data folder should be current working dir for portable version - return global.db_dir || path.join(homedir(), '.SwitchHosts') + return path.join(homedir(), '.SwitchHosts') } diff --git a/src/main/libs/getDataDir.ts b/src/main/libs/getDataDir.ts new file mode 100644 index 000000000..bb90b3732 --- /dev/null +++ b/src/main/libs/getDataDir.ts @@ -0,0 +1,17 @@ +/** + * @author: oldj + * @homepage: https://oldj.net + */ + +import * as path from 'path' +import { homedir } from 'os' + +export function getDefaultDataDir() { + return path.join(homedir(), '.SwitchHosts') +} + +export default (): string => { + // todo data folder should be current working dir for portable version + + return global.data_dir || getDefaultDataDir() +} diff --git a/src/main/main.ts b/src/main/main.ts index fe730fa64..7390808f9 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -17,10 +17,12 @@ import { app, BrowserWindow, ipcMain, nativeTheme } from 'electron' import windowStateKeeper from 'electron-window-state' import * as path from 'path' import { v4 as uuid4 } from 'uuid' +import { getSwhDb } from '@main/data' let win: BrowserWindow | null const createWindow = async () => { + await getSwhDb() const configs = await configAll() let main_window_state = windowStateKeeper({ diff --git a/src/main/types.d.ts b/src/main/types.d.ts index 78391ddd2..94057e4cc 100644 --- a/src/main/types.d.ts +++ b/src/main/types.d.ts @@ -7,7 +7,7 @@ import Tracer from '@main/libs/tracer' import { LocaleName } from '@root/common/i18n' import SwhDb from 'potdb' -import { BrowserWindow } from 'electron' +import { BrowserWindow, WebContents } from 'electron' import * as actions from './actions' export type Actions = typeof actions @@ -22,21 +22,21 @@ export interface IHostsWriteOptions { sudo_pswd?: string } +export interface IActionFunc { + sender: WebContents +} + declare global { - namespace NodeJS { - interface Global { - db_dir?: string - swhdb: SwhDb - cfgdb: SwhDb - localdb: SwhDb - ua: string // user agent - session_id: string // A random value, refreshed every time the app starts, used to identify different startup sessions. - main_win: BrowserWindow - find_win?: BrowserWindow | null - last_path?: string // the last path opened by SwitchHosts - tracer: Tracer - is_will_quit?: boolean - system_locale?: LocaleName - } - } + var data_dir: string | undefined + var swhdb: SwhDb + var cfgdb: SwhDb + var localdb: SwhDb + var ua: string // user agent + var session_id: string // A random value, refreshed every time the app starts, used to identify different startup sessions. + var main_win: BrowserWindow + var find_win: BrowserWindow | null + var last_path: string // the last path opened by SwitchHosts + var tracer: Tracer + var is_will_quit: boolean + var system_locale: LocaleName } diff --git a/src/renderer/components/Pref/Advanced.tsx b/src/renderer/components/Pref/Advanced.tsx index ab6e29255..b717ff5ce 100644 --- a/src/renderer/components/Pref/Advanced.tsx +++ b/src/renderer/components/Pref/Advanced.tsx @@ -6,10 +6,12 @@ import { useModel } from '@@/plugin-model/useModel' import { + Button, Checkbox, FormControl, FormHelperText, FormLabel, + HStack, Link, Tooltip, VStack, @@ -47,15 +49,19 @@ const PathLink = (props: { link: string }) => { const Advanced = (props: IProps) => { const { data, onChange } = props - const { lang } = useModel('useI18n') + const { i18n, lang } = useModel('useI18n') const [hosts_path, setHostsPath] = useState('') - const [data_path, setDataPath] = useState('') + const [data_dir, setDataDir] = useState('') + const [default_data_dir, setDefaultDataDir] = useState('') useEffect(() => { actions .getPathOfSystemHosts() .then((hosts_path) => setHostsPath(hosts_path)) - actions.getDataFolder().then((data_path) => setDataPath(data_path)) + actions.getDataDir().then((data_dir) => setDataDir(data_dir)) + actions + .getDefaultDataDir() + .then((default_data_dir) => setDefaultDataDir(default_data_dir)) }, []) return ( @@ -80,7 +86,37 @@ const Advanced = (props: IProps) => { {lang.where_is_my_data} {lang.your_data_is} - + + + + + {data_dir !== default_data_dir && ( + + )} + )