feat: more touch operations

This commit is contained in:
Gabe
2025-10-22 01:50:49 +08:00
parent 53e32d3031
commit 60b9653fd3
15 changed files with 730 additions and 550 deletions

View File

@@ -3,12 +3,16 @@ import { APP_CONSTS } from "../config";
import ContentFab from "../views/Action/ContentFab";
export class FabManager extends ShadowDomManager {
constructor({ translator, popupManager, fabConfig }) {
constructor({ translator, processActions, fabConfig }) {
super({
id: APP_CONSTS.fabID,
className: "notranslate",
reactComponent: ContentFab,
props: { translator, popupManager, fabConfig },
props: { translator, processActions, fabConfig },
});
if (!fabConfig?.isHide) {
this.show();
}
}
}

View File

@@ -1,14 +1,26 @@
import ShadowDomManager from "./shadowDomManager";
import { APP_CONSTS } from "../config";
import { APP_CONSTS, EVENT_KISS, MSG_POPUP_TOGGLE } from "../config";
import Action from "../views/Action";
export class PopupManager extends ShadowDomManager {
constructor({ translator }) {
constructor({ translator, processActions }) {
super({
id: APP_CONSTS.popupID,
className: "notranslate",
reactComponent: Action,
props: { translator },
props: { translator, processActions },
});
}
toggle(props) {
if (this.isVisible) {
document.dispatchEvent(
new CustomEvent(EVENT_KISS, {
detail: { action: MSG_POPUP_TOGGLE },
})
);
} else {
this.show(props || this._props);
}
}
}

View File

@@ -1,12 +1,47 @@
export function touchTapListener(fn, touchsLength) {
export function touchTapListener(fn, options = {}) {
const config = {
taps: 2,
fingers: 1,
delay: 300,
...options,
};
let maxTouches = 0;
let tapCount = 0;
let tapTimer = null;
const handleTouchStart = (e) => {
maxTouches = Math.max(maxTouches, e.touches.length);
};
const handleTouchend = (e) => {
if (e.touches.length === touchsLength) {
fn();
if (e.touches.length === 0) {
if (maxTouches === config.fingers) {
tapCount++;
clearTimeout(tapTimer);
if (tapCount === config.taps) {
fn(e);
tapCount = 0;
} else {
tapTimer = setTimeout(() => {
tapCount = 0;
}, config.delay);
}
} else {
tapCount = 0;
clearTimeout(tapTimer);
}
maxTouches = 0;
}
};
document.addEventListener("touchstart", handleTouchend);
document.addEventListener("touchstart", handleTouchStart, { passive: true });
document.addEventListener("touchend", handleTouchend, { passive: true });
return () => {
document.removeEventListener("touchstart", handleTouchend);
clearTimeout(tapTimer);
document.removeEventListener("touchstart", handleTouchStart);
document.removeEventListener("touchend", handleTouchend);
};
}

View File

@@ -1644,6 +1644,17 @@ export class Translator {
this.updateRule({ textStyle });
}
// 切换划词翻译
toggleTransbox() {
this.#setting.tranboxSetting.transOpen =
!this.#setting.tranboxSetting.transOpen;
}
// 切换输入框翻译
toggleInputTranslate() {
this.#setting.inputRule.transOpen = !this.#setting.inputRule.transOpen;
}
// 停止运行
stop() {
this.disable();

View File

@@ -4,9 +4,8 @@ import { InputTranslator } from "./inputTranslate";
import { TransboxManager } from "./tranbox";
import { shortcutRegister } from "./shortcut";
import { sendIframeMsg } from "./iframe";
import { newI18n } from "../config";
import { EVENT_KISS, newI18n } from "../config";
import { touchTapListener } from "./touch";
import { debounce } from "./utils";
import { PopupManager } from "./popupManager";
import { FabManager } from "./fabManager";
import {
@@ -20,6 +19,7 @@ import {
MSG_TRANS_PUTRULE,
MSG_OPEN_TRANBOX,
MSG_TRANSBOX_TOGGLE,
MSG_POPUP_TOGGLE,
MSG_MOUSEHOVER_TOGGLE,
MSG_TRANSINPUT_TOGGLE,
} from "../config";
@@ -57,16 +57,15 @@ export default class TranslatorManager {
if (!isIframe) {
this._transboxManager = new TransboxManager(setting);
this._inputTranslator = new InputTranslator(setting);
this._popupManager = new PopupManager({ translator: this._translator });
if (fabConfig && !fabConfig.isHide) {
this._fabManager = new FabManager({
translator: this._translator,
popupManager: this._popupManager,
fabConfig,
});
this._fabManager.show();
}
this._popupManager = new PopupManager({
translator: this._translator,
processActions: this.#processActions.bind(this),
});
this._fabManager = new FabManager({
translator: this._translator,
processActions: this.#processActions.bind(this),
fabConfig,
});
}
this.#windowMessageHandler = this.#handleWindowMessage.bind(this);
@@ -125,8 +124,8 @@ export default class TranslatorManager {
}
// 子模块
this._popupManager?.hide();
this._fabManager?.hide();
this._popupManager?.destroy();
this._fabManager?.destroy();
this._transboxManager?.disable();
this._inputTranslator?.disable();
this._translator.stop();
@@ -151,11 +150,39 @@ export default class TranslatorManager {
return;
}
const handleTap = debounce(() => {
const handleTap = () => {
this.#processActions({ action: MSG_TRANS_TOGGLE });
}, 300);
};
this.#clearTouchListener = touchTapListener(handleTap, touchTranslate);
switch (touchTranslate) {
case 2:
case 3:
case 4:
this.#clearTouchListener = touchTapListener(handleTap, {
taps: 1,
fingers: touchTranslate,
});
break;
case 5:
this.#clearTouchListener = touchTapListener(handleTap, {
taps: 2,
fingers: 1,
});
break;
case 6:
this.#clearTouchListener = touchTapListener(handleTap, {
taps: 3,
fingers: 1,
});
break;
case 7:
this.#clearTouchListener = touchTapListener(handleTap, {
taps: 2,
fingers: 2,
});
break;
default:
}
}
#handleWindowMessage(event) {
@@ -182,7 +209,7 @@ export default class TranslatorManager {
this.#processActions({ action: MSG_TRANS_TOGGLE_STYLE })
),
shortcutRegister(shortcuts[OPT_SHORTCUT_POPUP], () =>
this._popupManager.toggle()
this.#processActions({ action: MSG_POPUP_TOGGLE })
),
shortcutRegister(shortcuts[OPT_SHORTCUT_SETTING], () =>
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank")
@@ -210,7 +237,7 @@ export default class TranslatorManager {
),
GM.registerMenuCommand(
i18n("open_menu"),
() => this._popupManager.toggle(),
() => this.#processActions({ action: MSG_POPUP_TOGGLE }),
"K"
),
GM.registerMenuCommand(
@@ -239,16 +266,25 @@ export default class TranslatorManager {
this._translator.updateRule(args);
break;
case MSG_OPEN_TRANBOX:
this._transboxManager?.enable();
document.dispatchEvent(
new CustomEvent(EVENT_KISS, {
detail: { action: MSG_OPEN_TRANBOX },
})
);
break;
case MSG_POPUP_TOGGLE:
this._popupManager?.toggle();
break;
case MSG_TRANSBOX_TOGGLE:
this._transboxManager?.toggle();
this._translator.toggleTransbox();
break;
case MSG_MOUSEHOVER_TOGGLE:
this._translator.toggleMouseHover();
break;
case MSG_TRANSINPUT_TOGGLE:
this._inputTranslator?.toggle();
this._translator.toggleInputTranslate();
break;
default:
logger.info(`Message action is unavailable: ${action}`);