diff --git a/src/background.js b/src/background.js index 4812cda..e5d371e 100644 --- a/src/background.js +++ b/src/background.js @@ -20,7 +20,7 @@ import { fetchData, fetchPool } from "./libs/fetch"; * 插件安装 */ browser.runtime.onInstalled.addListener(() => { - console.log("onInstalled"); + console.log("KISS Translator onInstalled"); storage.trySetObj(STOKEY_SETTING, DEFAULT_SETTING); storage.trySetObj(STOKEY_RULES, DEFAULT_RULES); storage.trySetObj(STOKEY_SYNC, DEFAULT_SYNC); @@ -30,7 +30,7 @@ browser.runtime.onInstalled.addListener(() => { * 浏览器启动 */ browser.runtime.onStartup.addListener(async () => { - console.log("onStartup"); + console.log("browser onStartup"); // 同步数据 await syncAll(); diff --git a/src/hooks/Rules.js b/src/hooks/Rules.js index e1ad5a9..72f571c 100644 --- a/src/hooks/Rules.js +++ b/src/hooks/Rules.js @@ -25,11 +25,7 @@ export function useRules() { const updateAt = sync.opt?.rulesUpdateAt ? Date.now() : 0; await storage.setObj(STOKEY_RULES, rules); await sync.update({ rulesUpdateAt: updateAt }); - try { - await syncRules(); - } catch (err) { - console.log("[sync rules]", err); - } + syncRules(); }; const add = async (rule) => { diff --git a/src/hooks/Setting.js b/src/hooks/Setting.js index a5cc8d7..ad19a9c 100644 --- a/src/hooks/Setting.js +++ b/src/hooks/Setting.js @@ -2,6 +2,7 @@ import { STOKEY_SETTING } from "../config"; import storage from "../libs/storage"; import { useStorages } from "./Storage"; import { useSync } from "./Sync"; +import { syncSetting } from "../libs/sync"; /** * 设置hook @@ -22,5 +23,6 @@ export function useSettingUpdate() { const updateAt = sync.opt?.settingUpdateAt ? Date.now() : 0; await storage.putObj(STOKEY_SETTING, obj); await sync.update({ settingUpdateAt: updateAt }); + syncSetting(); }; } diff --git a/src/libs/sync.js b/src/libs/sync.js index 38d590e..4c7a848 100644 --- a/src/libs/sync.js +++ b/src/libs/sync.js @@ -13,62 +13,66 @@ import { apiSyncData } from "../apis"; const loadOpt = async () => (await storage.getObj(STOKEY_SYNC)) || DEFAULT_SYNC; export const syncSetting = async () => { - const { syncUrl, syncKey, settingUpdateAt } = await loadOpt(); - if (!syncUrl || !syncKey) { - return; - } + try { + const { syncUrl, syncKey, settingUpdateAt } = await loadOpt(); + if (!syncUrl || !syncKey) { + return; + } - const setting = await getSetting(); - const res = await apiSyncData(syncUrl, syncKey, { - key: KV_SETTING_KEY, - value: setting, - updateAt: settingUpdateAt, - }); + const setting = await getSetting(); + const res = await apiSyncData(syncUrl, syncKey, { + key: KV_SETTING_KEY, + value: setting, + updateAt: settingUpdateAt, + }); - if (res && res.updateAt > settingUpdateAt) { - await storage.putObj(STOKEY_SYNC, { - settingUpdateAt: res.updateAt, - settingSyncAt: res.updateAt, - }); - await storage.setObj(STOKEY_SETTING, res.value); - } else { - await storage.putObj(STOKEY_SYNC, { - settingSyncAt: res.updateAt, - }); + if (res && res.updateAt > settingUpdateAt) { + await storage.putObj(STOKEY_SYNC, { + settingUpdateAt: res.updateAt, + settingSyncAt: res.updateAt, + }); + await storage.setObj(STOKEY_SETTING, res.value); + } else { + await storage.putObj(STOKEY_SYNC, { + settingSyncAt: res.updateAt, + }); + } + } catch (err) { + console.log("[sync setting]", err); } }; export const syncRules = async () => { - const { syncUrl, syncKey, rulesUpdateAt } = await loadOpt(); - if (!syncUrl || !syncKey) { - return; - } + try { + const { syncUrl, syncKey, rulesUpdateAt } = await loadOpt(); + if (!syncUrl || !syncKey) { + return; + } - const rules = await getRules(); - const res = await apiSyncData(syncUrl, syncKey, { - key: KV_RULES_KEY, - value: rules, - updateAt: rulesUpdateAt, - }); + const rules = await getRules(); + const res = await apiSyncData(syncUrl, syncKey, { + key: KV_RULES_KEY, + value: rules, + updateAt: rulesUpdateAt, + }); - if (res && res.updateAt > rulesUpdateAt) { - await storage.putObj(STOKEY_SYNC, { - rulesUpdateAt: res.updateAt, - rulesSyncAt: res.updateAt, - }); - await storage.setObj(STOKEY_RULES, res.value); - } else { - await storage.putObj(STOKEY_SYNC, { - rulesSyncAt: res.updateAt, - }); + if (res && res.updateAt > rulesUpdateAt) { + await storage.putObj(STOKEY_SYNC, { + rulesUpdateAt: res.updateAt, + rulesSyncAt: res.updateAt, + }); + await storage.setObj(STOKEY_RULES, res.value); + } else { + await storage.putObj(STOKEY_SYNC, { + rulesSyncAt: res.updateAt, + }); + } + } catch (err) { + console.log("[sync rules]", err); } }; export const syncAll = async () => { - try { - await syncSetting(); - await syncRules(); - } catch (err) { - console.log("[sync all]", err); - } + await syncSetting(); + await syncRules(); }; diff --git a/src/views/Action/Draggable.js b/src/views/Action/Draggable.js index bc3c494..b70bd18 100644 --- a/src/views/Action/Draggable.js +++ b/src/views/Action/Draggable.js @@ -30,6 +30,8 @@ const getEdgePosition = ( edge = "top"; top = 0; } + left = limitNumber(left, 0, windowWidth - width); + top = limitNumber(top, 0, windowHeight - height); return { x: left, y: top, edge, hide: false }; }; diff --git a/src/views/Options/Layout.js b/src/views/Options/Layout.js index 8a98419..b811f47 100644 --- a/src/views/Options/Layout.js +++ b/src/views/Options/Layout.js @@ -6,7 +6,6 @@ import Box from "@mui/material/Box"; import Navigator from "./Navigator"; import Header from "./Header"; import { useTheme } from "@mui/material/styles"; -import { syncAll } from "../../libs/sync"; export default function Layout() { const navWidth = 256; @@ -21,7 +20,6 @@ export default function Layout() { useEffect(() => { setOpen(false); - syncAll(); }, [location]); return ( diff --git a/src/views/Options/Rules.js b/src/views/Options/Rules.js index ac1630a..6e18d24 100644 --- a/src/views/Options/Rules.js +++ b/src/views/Options/Rules.js @@ -122,6 +122,7 @@ function RuleFields({ rule, rules, setShow }) { disabled={rule?.pattern === "*" || disabled} onChange={handleChange} onFocus={handleFocus} + multiline /> @@ -301,6 +300,25 @@ function RuleFields({ rule, rules, setShow }) { ); } +function RuleAccordion({ rule, rules }) { + const [expanded, setExpanded] = useState(false); + + const handleChange = (e) => { + setExpanded((pre) => !pre); + }; + + return ( + + }> + {rule.pattern} + + + {expanded && } + + + ); +} + function DownloadButton({ data, text, fileName }) { const handleClick = (e) => { e.preventDefault(); @@ -405,14 +423,7 @@ export default function Rules() { {rules.list.map((rule) => ( - - }> - {rule.pattern} - - - - - + ))} diff --git a/src/views/Options/Setting.js b/src/views/Options/Setting.js index c84d201..ff4180e 100644 --- a/src/views/Options/Setting.js +++ b/src/views/Options/Setting.js @@ -6,15 +6,37 @@ import MenuItem from "@mui/material/MenuItem"; import FormControl from "@mui/material/FormControl"; import Select from "@mui/material/Select"; import { useSetting, useSettingUpdate } from "../../hooks/Setting"; -import { limitNumber } from "../../libs/utils"; +import { limitNumber, debounce } from "../../libs/utils"; import { useI18n } from "../../hooks/I18n"; import { UI_LANGS } from "../../config"; +import { useMemo } from "react"; export default function Settings() { const i18n = useI18n(); const setting = useSetting(); const updateSetting = useSettingUpdate(); + const handleChange = useMemo( + () => + debounce((e) => { + e.preventDefault(); + let { name, value } = e.target; + switch (name) { + case "fetchLimit": + value = limitNumber(value, 1, 100); + break; + case "fetchInterval": + value = limitNumber(value, 0, 5000); + break; + default: + } + updateSetting({ + [name]: value, + }); + }, 500), + [updateSetting] + ); + if (!setting) { return; } @@ -37,13 +59,10 @@ export default function Settings() { {i18n("ui_lang")} { - updateSetting({ - clearCache: e.target.value, - }); - }} + onChange={handleChange} > {i18n("clear_cache_never")} {i18n("clear_cache_restart")} @@ -96,60 +106,43 @@ export default function Settings() { { - updateSetting({ - googleUrl: e.target.value, - }); - }} + onChange={handleChange} /> { - updateSetting({ - openaiUrl: e.target.value, - }); - }} + onChange={handleChange} /> { - updateSetting({ - openaiKey: e.target.value, - }); - }} + onChange={handleChange} /> { - updateSetting({ - openaiModel: e.target.value, - }); - }} + onChange={handleChange} /> { - updateSetting({ - openaiPrompt: e.target.value, - }); - }} + onChange={handleChange} multiline - minRows={2} - maxRows={10} /> diff --git a/src/views/Options/SyncSetting.js b/src/views/Options/SyncSetting.js index 9805a89..cbe7330 100644 --- a/src/views/Options/SyncSetting.js +++ b/src/views/Options/SyncSetting.js @@ -3,23 +3,33 @@ import Stack from "@mui/material/Stack"; import TextField from "@mui/material/TextField"; import { useI18n } from "../../hooks/I18n"; import { useSync } from "../../hooks/Sync"; -import { syncAll } from "../../libs/sync"; import Alert from "@mui/material/Alert"; import Link from "@mui/material/Link"; import { URL_KISS_WORKER } from "../../config"; +import { debounce } from "../../libs/utils"; +import { useMemo } from "react"; export default function SyncSetting() { const i18n = useI18n(); const sync = useSync(); + const handleChange = useMemo( + () => + debounce((e) => { + e.preventDefault(); + const { name, value } = e.target; + sync.update({ + [name]: value, + }); + }, 500), + [sync] + ); + if (!sync.opt) { return; } const { syncUrl, syncKey } = sync.opt; - const handleSyncBlur = () => { - syncAll(); - }; return ( @@ -29,13 +39,9 @@ export default function SyncSetting() { { - sync.update({ - syncUrl: e.target.value, - }); - }} - onBlur={handleSyncBlur} + onChange={handleChange} helperText={ {i18n("about_sync_api")} } @@ -45,13 +51,9 @@ export default function SyncSetting() { size="small" type="password" label={i18n("data_sync_key")} + name="syncKey" defaultValue={syncKey} - onChange={(e) => { - sync.update({ - syncKey: e.target.value, - }); - }} - onBlur={handleSyncBlur} + onChange={handleChange} /> diff --git a/src/views/Options/index.js b/src/views/Options/index.js index cebd928..32064d5 100644 --- a/src/views/Options/index.js +++ b/src/views/Options/index.js @@ -10,31 +10,34 @@ import { useEffect, useState } from "react"; import { isGm } from "../../libs/browser"; import { sleep } from "../../libs/utils"; import CircularProgress from "@mui/material/CircularProgress"; +import { syncAll } from "../../libs/sync"; export default function Options() { const [error, setError] = useState(false); const [ready, setReady] = useState(false); useEffect(() => { - if (!isGm) { - return; - } - (async () => { - let i = 0; - for (;;) { - if (window.APP_NAME === process.env.REACT_APP_NAME) { - setReady(true); - break; - } + if (isGm) { + // 等待GM注入 + let i = 0; + for (;;) { + if (window.APP_NAME === process.env.REACT_APP_NAME) { + setReady(true); + break; + } - if (++i > 8) { - setError(true); - break; - } + if (++i > 8) { + setError(true); + break; + } - await sleep(1000); + await sleep(1000); + } } + + // 同步数据 + syncAll(); })(); }, []);