From 895d44f60bfda1a754346e637ce52696d2322bac Mon Sep 17 00:00:00 2001 From: divisey <18656007202@163.com> Date: Wed, 4 Sep 2024 15:05:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20dict=20import=20update?= =?UTF-8?q?=20(#1040)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- enjoy/src/i18n/en.json | 5 +- enjoy/src/i18n/zh-CN.json | 5 +- enjoy/src/main/decompresser.ts | 8 +++- enjoy/src/main/dict.ts | 22 ++++----- enjoy/src/preload.ts | 9 +++- .../dict-settings/dict-import-button.tsx | 23 +++------- .../dict-settings/installed-dict-list.tsx | 46 ++++++++++++++++++- enjoy/src/types/enjoy-app.d.ts | 1 + enjoy/src/types/index.d.ts | 3 +- 9 files changed, 83 insertions(+), 39 deletions(-) diff --git a/enjoy/src/i18n/en.json b/enjoy/src/i18n/en.json index 12dfa491..38899eed 100644 --- a/enjoy/src/i18n/en.json +++ b/enjoy/src/i18n/en.json @@ -772,13 +772,14 @@ "removeDictDescription": "It will delete the dictionary file from your local computer and you will have to download it again next time.", "downloadingDict": "Downloading", "removeDefault": "No longer as Default", - "selectAdaptionDictTitle": "Select adapted dictionary folder", + "selectAdaptionDictTitle": "Select adapted dictionary", "selectMdictFileOrDirTitle": "Select dict files (.mdx and optional .mdd) or folder", - "dictImportSlowTip": "It may take longer if the dictionary file is large.", + "dictImportSlowTip": "Checking...(It may take longer if the dictionary file is large.)", "importAdaptionDict": "Import the adapted dictionary", "adaptionDictTip": "The adapted dictionaries have better usability.", "howToDownload": "How to download?", "selectDir": "Select Folder", + "selectFile": "Select File", "importMdictFile": "Import the original dictionary file", "mdictFileTip": "Directly import .mdx .mdd format files (.mdx files are required, .mdd files are optional and can have multiple), but there may be problems with style and usability." } diff --git a/enjoy/src/i18n/zh-CN.json b/enjoy/src/i18n/zh-CN.json index 5af46464..6cc0d2b2 100644 --- a/enjoy/src/i18n/zh-CN.json +++ b/enjoy/src/i18n/zh-CN.json @@ -772,13 +772,14 @@ "removeDictDescription": "此操作将会从本地删除词典文件,下次安装需要重新下载", "downloadingDict": "正在下载", "removeDefault": "不再设置为默认", - "selectAdaptionDictTitle": "选择预先适配的词典文件夹", + "selectAdaptionDictTitle": "选择预先适配的词典文件", "selectMdictFileOrDirTitle": "选择词典文件 (.mdx 和可选的 .mdd 文件) or 文件夹", - "dictImportSlowTip": "词典文件较大时可能需要的时间比较长", + "dictImportSlowTip": "正在检查...(词典文件较大时可能需要的时间比较长)", "importAdaptionDict": "导入已经适配好的词典", "adaptionDictTip": "已经适配好的词典可用性较好。", "howToDownload": "如何下载?", "selectDir": "选择文件夹", + "selectFile": "选择文件", "importMdictFile": "导入原词典文件", "mdictFileTip": "直接导入 .mdx .mdd 格式的文件 (.mdx 文件是必须的,.mdd 文件是可选的且可以有多个),不过样式和可用性可能存在问题。" } diff --git a/enjoy/src/main/decompresser.ts b/enjoy/src/main/decompresser.ts index 84878b43..39585413 100644 --- a/enjoy/src/main/decompresser.ts +++ b/enjoy/src/main/decompresser.ts @@ -23,8 +23,8 @@ class Decompresser { await directory.extract({ path: task.destPath + ".depressing" }); await fs.rename(task.destPath + ".depressing", task.destPath); - await fs.remove(task.filePath); + this.done(task); this.remove(task); } @@ -46,7 +46,7 @@ class Decompresser { if (currentTask) { setTimeout(() => { this.onProgress(task, total); - }, 5000); + }, 1000); } } @@ -73,6 +73,10 @@ class Decompresser { mainWin.win.webContents.send("decompress-tasks-update", this.tasks); } + done(task: DecompressTask) { + mainWin.win.webContents.send("decompress-task-done", task); + } + registerIpcHandlers() { ipcMain.handle("decompress-tasks", () => { return this.tasks; diff --git a/enjoy/src/main/dict.ts b/enjoy/src/main/dict.ts index a120732c..4b0fbc85 100644 --- a/enjoy/src/main/dict.ts +++ b/enjoy/src/main/dict.ts @@ -7,6 +7,7 @@ import { DICTS } from "@/constants/dicts"; import sqlite3, { Database } from "sqlite3"; import settings from "./settings"; import { hashFile } from "@/main/utils"; +import decompresser from "./decompresser"; const logger = log.scope("dict"); const sqlite = sqlite3.verbose(); @@ -23,17 +24,10 @@ export class DictHandler { return _path; } - async import(dir: string) { - const files = await fs.readdir(dir); + async import(_path: string) { + const hash = await hashFile(_path, { algo: "md5" }); + const dict = DICTS.find((dict) => dict.hash === hash); - const sqlFileName = files.find((file) => file.match(/\.sqlite$/)); - if (!sqlFileName) { - throw new Error("SQLite file not found"); - } - - const sqlFilePath = path.join(dir, sqlFileName); - const hash = await hashFile(sqlFilePath, { algo: "md5" }); - const dict = DICTS.find((dict) => dict.sqlFileHash === hash); if (!dict) { throw new Error("SQLite file not match with any perset dictionary"); } @@ -42,8 +36,12 @@ export class DictHandler { throw new Error("Current dict is already installed"); } - await fs.copy(dir, path.join(this.dictsPath, dict.name), { - recursive: true, + decompresser.depress({ + id: `dict-${dict.name}`, + type: "dict", + title: dict.title, + filePath: _path, + destPath: path.join(this.dictsPath, dict.name), }); } diff --git a/enjoy/src/preload.ts b/enjoy/src/preload.ts index 9f7a8384..a10b1298 100644 --- a/enjoy/src/preload.ts +++ b/enjoy/src/preload.ts @@ -557,12 +557,17 @@ contextBridge.exposeInMainWorld("__ENJOY_APP__", { }, }, decompress: { + onComplete: ( + callback: (event: IpcRendererEvent, task: DecompressTask) => void + ) => ipcRenderer.on("decompress-task-done", callback), onUpdate: ( callback: (event: IpcRendererEvent, tasks: DecompressTask[]) => void ) => ipcRenderer.on("decompress-tasks-update", callback), dashboard: () => ipcRenderer.invoke("decompress-tasks"), - removeAllListeners: () => - ipcRenderer.removeAllListeners("decompress-tasks-update"), + removeAllListeners: () => { + ipcRenderer.removeAllListeners("decompress-tasks-update"); + ipcRenderer.removeAllListeners("decompress-tasks-done"); + }, }, download: { onState: ( diff --git a/enjoy/src/renderer/components/preferences/dict-settings/dict-import-button.tsx b/enjoy/src/renderer/components/preferences/dict-settings/dict-import-button.tsx index 448a9421..f789f745 100644 --- a/enjoy/src/renderer/components/preferences/dict-settings/dict-import-button.tsx +++ b/enjoy/src/renderer/components/preferences/dict-settings/dict-import-button.tsx @@ -1,4 +1,4 @@ -import { useState, useContext } from "react"; +import { useState, useContext, useEffect } from "react"; import { AppSettingsProviderContext, DictProviderContext, @@ -20,7 +20,6 @@ export const DictImportButton = () => { const { EnjoyApp } = useContext(AppSettingsProviderContext); const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); - const [tipVisible, setTipVisible] = useState(false); const handleOpen = (value: boolean) => { setOpen(value); @@ -29,17 +28,12 @@ export const DictImportButton = () => { const handleAdaptationDictImport = async () => { const pathes = await EnjoyApp.dialog.showOpenDialog({ title: t("selectAdaptionDictTitle"), - properties: ["openDirectory"], + properties: ["openFile"], + filters: [{ name: "zip", extensions: [".zip"] }], }); if (!pathes[0]) return; - setLoading(true); - setTimeout(() => { - if (loading) { - setTipVisible(true); - } - }, 10000); try { await EnjoyApp.dict.import(pathes[0]); @@ -49,7 +43,6 @@ export const DictImportButton = () => { } setLoading(false); - setTipVisible(false); reload(); }; @@ -75,11 +68,9 @@ export const DictImportButton = () => {
- {tipVisible && ( -
- {t("dictImportSlowTip")} -
- )} +
+ {t("dictImportSlowTip")} +
) : (
@@ -102,7 +93,7 @@ export const DictImportButton = () => {
diff --git a/enjoy/src/renderer/components/preferences/dict-settings/installed-dict-list.tsx b/enjoy/src/renderer/components/preferences/dict-settings/installed-dict-list.tsx index e5484950..91ff0e13 100644 --- a/enjoy/src/renderer/components/preferences/dict-settings/installed-dict-list.tsx +++ b/enjoy/src/renderer/components/preferences/dict-settings/installed-dict-list.tsx @@ -17,15 +17,34 @@ import { AlertDialogAction, } from "@renderer/components/ui"; import { t } from "i18next"; +import { LoaderIcon } from "lucide-react"; export const InstalledDictList = function () { + const { EnjoyApp } = useContext(AppSettingsProviderContext); const { installedDicts, reload } = useContext(DictProviderContext); + const [tasks, setTasks] = useState([]); useEffect(() => { reload(); + + EnjoyApp.decompress.dashboard().then((_tasks) => { + setTasks(_tasks.filter((_task) => _task.type === "dict")); + }); + + EnjoyApp.decompress.onComplete((_, task) => { + if (task.type === "dict") reload(); + }); + + EnjoyApp.decompress.onUpdate((_, _tasks) => { + setTasks(_tasks.filter((_task) => _task.type === "dict")); + }); + + return () => { + EnjoyApp.decompress.removeAllListeners(); + }; }, []); - if (installedDicts.length === 0) { + if (installedDicts.length === 0 && tasks.length === 0) { return (
{t("dictEmpty")}
); @@ -33,6 +52,10 @@ export const InstalledDictList = function () { return ( <> + {tasks.map((task) => ( + + ))} + {installedDicts.map((item) => ( ))} @@ -40,6 +63,22 @@ export const InstalledDictList = function () { ); }; +const DecompressDictItem = function ({ task }: { task: DecompressTask }) { + return ( +
+
+ {task.title} +
+ +
+ {t("decompressing")} + {task.progress || 0}% + +
+
+ ); +}; + const InstalledDictItem = function ({ dict }: { dict: Dict }) { const { EnjoyApp } = useContext(AppSettingsProviderContext); const { settings, setDefault, reload, remove, removed } = @@ -89,7 +128,10 @@ const InstalledDictItem = function ({ dict }: { dict: Dict }) { function renderActions() { if (removing) { return ( - {t("removing")} +
+ {t("removing")} + +
); } diff --git a/enjoy/src/types/enjoy-app.d.ts b/enjoy/src/types/enjoy-app.d.ts index 71bb2edd..9c3c6978 100644 --- a/enjoy/src/types/enjoy-app.d.ts +++ b/enjoy/src/types/enjoy-app.d.ts @@ -317,6 +317,7 @@ type EnjoyAppType = { ) => Promise; }; decompress: { + onComplete: (callback: (event, task: DecompressTask) => void) => void; onUpdate: (callback: (event, tasks: DecompressTask[]) => void) => void; dashboard: () => Promise; removeAllListeners: () => void; diff --git a/enjoy/src/types/index.d.ts b/enjoy/src/types/index.d.ts index 858aa436..d1708a47 100644 --- a/enjoy/src/types/index.d.ts +++ b/enjoy/src/types/index.d.ts @@ -27,9 +27,10 @@ type DownloadStateType = { type DecompressTask = { id: string; + type: string; + title: string; filePath: string; destPath: string; - hash: string; progress?: string; };