Browse Source

Merge branch 'feature/change-data-dir' into develop

oldj 3 years ago
parent
commit
2be4908fbc

+ 6 - 0
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',

+ 6 - 0
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',

+ 4 - 0
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: '全选',

+ 68 - 0
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<string | undefined> {
+  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
+}

+ 8 - 0
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()

+ 0 - 8
src/main/actions/getDataFolder.ts

@@ -1,8 +0,0 @@
-/**
- * @author: oldj
- * @homepage: https://oldj.net
- */
-
-import getDataFolder from '@main/libs/getDataFolder'
-
-export default async () => getDataFolder()

+ 8 - 0
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()

+ 3 - 1
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'

+ 1 - 1
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'

+ 1 - 1
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'

+ 3 - 2
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)

+ 23 - 19
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<PotDb> {
+  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 }

+ 1 - 1
src/main/libs/getDataFolder.ts → 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')
 }

+ 17 - 0
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()
+}

+ 2 - 0
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({

+ 17 - 17
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
 }

+ 40 - 4
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) => {
       <FormControl>
         <FormLabel>{lang.where_is_my_data}</FormLabel>
         <FormHelperText mb={2}>{lang.your_data_is}</FormHelperText>
-        <PathLink link={data_path} />
+        <HStack>
+          <PathLink link={data_dir} />
+          <Button
+            variant="link"
+            onClick={async () => {
+              let r = await actions.cmdChangeDataDir()
+              console.log(r)
+            }}
+          >
+            {lang.change}
+          </Button>
+
+          {data_dir !== default_data_dir && (
+            <Button
+              variant="link"
+              onClick={async () => {
+                if (
+                  !confirm(
+                    i18n.trans('reset_data_dir_confirm', [default_data_dir]),
+                  )
+                ) {
+                  return
+                }
+                let r = await actions.cmdChangeDataDir(true)
+                console.log(r)
+              }}
+            >
+              {lang.reset}
+            </Button>
+          )}
+        </HStack>
       </FormControl>
     </VStack>
   )