import { AnyTouch, log, utils } from "@/env";
import { GenerateData } from "@/main/data/NetDiskGenerateDataUtils";
import { NetDiskViewRightClickMenu } from "@/main/view/NetDiskViewRightClickMenu";
import { CommonUtil } from "@components/utils/CommonUtil";
import DOMUtils from "@whitesev/domutils";
import { NetDiskGlobalData } from "@/main/data/NetDiskGlobalData";
import { NetDiskView } from "../NetDiskView";
import { NetDiskSettingView } from "../setting/NetDiskSettingView";
import indexCSS from "./index.css?raw";
export const NetDiskSuspensionConfig = {
position: {
/** 悬浮按钮位置的x坐标 */
suspensionX: GenerateData("suspensionX", DOMUtils.width(window) - 50),
/** 悬浮按钮位置的y坐标 */
suspensionY: GenerateData("suspensionY", (DOMUtils.height(window) - 50) / 2),
/** 悬浮按钮所在位置的最大x */
suspensionMaxX: GenerateData("susponsionMax-x", DOMUtils.width(window) - 50),
/** 悬浮按钮所在位置的最小y */
suspensionMaxY: GenerateData("suspensionMax-y", DOMUtils.height(window) - 50),
/** 悬浮按钮是否在右边 */
isRight: GenerateData("isRight", false),
},
mode: {
/** 当前悬浮按钮调用弹窗的模式 */
current_suspension_smallwindow_mode: GenerateData(
"current_suspension_smallwindow_mode",
"suspension" as "suspension" | "smallwindow" | "window"
),
},
};
export const NetDiskSuspension = {
$el: {
/**
* 按钮元素
*/
$suspension: null as any as HTMLDivElement,
/**
* 按钮元素的动态z-index的style元素
*/
$suspensionZIndexStyle: null as any as HTMLStyleElement,
},
$data: {
/** 是否已显示 */
isShow: false,
/** 是否已设置所有的事件 */
isInitAllEvent: false,
/** 是否正在切换背景 */
isSwitchBackground: false,
},
/**
* 初始化
*/
init() {
if (!this.$data.isShow) {
this.$data.isShow = true;
this.createElement();
this.updateZIndex();
this.updatePosition(true);
}
if (!this.$data.isInitAllEvent) {
this.$data.isInitAllEvent = true;
this.setAllEvent();
this.setResizeEventListener();
}
this.changeBackground();
this.show();
},
/**
* 显示悬浮按钮
*/
show() {
DOMUtils.css(this.$el.$suspension, { display: "" });
},
/**
* 隐藏悬浮按钮
*/
hide() {
DOMUtils.css(this.$el.$suspension, { display: "none" });
},
/**
* 创建按钮元素
*/
createElement() {
if (NetDiskGlobalData.suspension.size.value < 15) {
// 大小不能小于 15px
NetDiskGlobalData.suspension.size.value = 15;
}
if (NetDiskGlobalData.suspension.size.value > 250) {
// 大小不能大于 250px
NetDiskGlobalData.suspension.size.value = 250;
}
if (NetDiskGlobalData.suspension.opacity.value < 0.1) {
// 透明度不能小于 0.1
NetDiskGlobalData.suspension.opacity.value = 0.1;
}
if (NetDiskGlobalData.suspension.opacity.value > 1.0) {
// 透明度不能大于 1.0
NetDiskGlobalData.suspension.opacity.value = 1.0;
}
const $shadowContainer = DOMUtils.createElement("div", {
className: "whitesev-suspension-shadow-container",
});
const $shadowRoot = $shadowContainer.attachShadow({ mode: "open" });
this.$el.$suspension = DOMUtils.createElement("div", {
id: "whitesevSuspensionId",
className: "whitesevSuspension",
innerHTML: /*html*/ `
`,
});
// 设置位置信息
DOMUtils.css(this.$el.$suspension, {
width: `${NetDiskGlobalData.suspension.size.value}px`,
height: `${NetDiskGlobalData.suspension.size.value}px`,
opacity: `${NetDiskGlobalData.suspension.opacity.value}`,
});
this.$el.$suspensionZIndexStyle = this.$el.$suspension.querySelector("style[data-z-index]")!;
$shadowRoot.appendChild(this.$el.$suspension);
(document.body || document.documentElement).appendChild($shadowContainer);
},
/**
* 设置 悬浮按钮所有事件
*/
setAllEvent() {
const needDragElement = NetDiskView.$inst.suspension.$el.$suspension;
const $drag = new AnyTouch(needDragElement);
let netDiskLinkViewTimer: number | undefined = void 0;
let moveFlag = false;
// 是否是双击
let isDouble = false;
// 点击元素,left偏移
let clickElementLeftOffset = 0;
// 点击元素,top偏移
let clickElementTopOffset = 0;
// 设置悬浮按钮 按下事件
$drag.on("pan", (event) => {
if (!moveFlag) {
moveFlag = true;
let rect = needDragElement.getBoundingClientRect();
clickElementLeftOffset = event.x - rect.left;
clickElementTopOffset = event.y - rect.top;
DOMUtils.css(needDragElement, {
cursor: "move",
transition: "none",
});
}
// 按下
if (event.phase === "start") {
// 更新z-index
this.updateZIndex();
}
// 移动
if (event.phase === "move") {
// 悬浮按钮大小不能超过250px
// left偏移最大值
const maxLeftOffset = DOMUtils.width(window) - NetDiskGlobalData.suspension.size.value;
// top偏移的最大值
const maxTopOffset = DOMUtils.height(window) - NetDiskGlobalData.suspension.size.value;
// 当前移动的left偏移
let currentSuspensionLeftOffset = event.x - clickElementLeftOffset;
// 当前移动的top偏移
let currentSuspensionTopOffset = event.y - clickElementTopOffset;
// 不允许超过窗口最大宽度
currentSuspensionLeftOffset =
currentSuspensionLeftOffset > maxLeftOffset ? maxLeftOffset : currentSuspensionLeftOffset;
// 不允许超过窗口最大高度
currentSuspensionTopOffset =
currentSuspensionTopOffset > maxTopOffset ? maxTopOffset : currentSuspensionTopOffset;
// 不允许小于0
currentSuspensionLeftOffset = currentSuspensionLeftOffset < 0 ? 0 : currentSuspensionLeftOffset;
// 不允许小于0
currentSuspensionTopOffset = currentSuspensionTopOffset < 0 ? 0 : currentSuspensionTopOffset;
NetDiskSuspension.savePosition({
x: currentSuspensionLeftOffset,
y: currentSuspensionTopOffset,
});
DOMUtils.css(needDragElement, {
left: currentSuspensionLeftOffset + "px",
top: currentSuspensionTopOffset + "px",
});
}
// 松开
if (event.phase === "end") {
moveFlag = false;
DOMUtils.css(needDragElement, {
cursor: "auto",
});
// 获取当前悬浮按钮left偏移
const currentSuspensionLeftOffset = parseInt(DOMUtils.css(needDragElement, "left"));
if (NetDiskGlobalData.suspension["suspended-button-adsorption-edge"].value) {
let setCSSLeft = 0;
// 判断悬浮按钮是否在右边区域
if (currentSuspensionLeftOffset >= DOMUtils.width(window) / 2) {
// 设置悬浮按钮的left偏移
setCSSLeft = DOMUtils.width(window) - NetDiskGlobalData.suspension.size.value;
if (CommonUtil.isTopWindow()) {
NetDiskSuspensionConfig.position.isRight.value = true;
}
} else {
if (CommonUtil.isTopWindow()) {
NetDiskSuspensionConfig.position.isRight.value = false;
}
}
NetDiskSuspension.savePosition({
x: setCSSLeft,
});
DOMUtils.css(needDragElement, {
left: setCSSLeft + "px",
});
}
DOMUtils.css(needDragElement, {
transition: "left 300ms ease 0s",
});
// 更新z-index
this.updateZIndex();
}
});
// 设置悬浮按钮 点击/按下事件
$drag.on("tap", function () {
clearTimeout(netDiskLinkViewTimer);
netDiskLinkViewTimer = void 0;
if (isDouble) {
isDouble = false;
// 判定为双击
NetDiskSettingView.show();
} else {
netDiskLinkViewTimer = setTimeout(() => {
isDouble = false;
// 隐藏悬浮按钮
NetDiskView.$inst.suspension.hide();
const behaviorModeIsSmallWindow = NetDiskGlobalData.features["netdisk-behavior-mode"].value
.toLowerCase()
.includes("smallwindow");
if (behaviorModeIsSmallWindow !== NetDiskView.$inst.linkView.$data.isSmallWindow) {
NetDiskView.$inst.linkView.destory();
}
NetDiskView.$inst.linkView.show();
}, 200);
isDouble = true;
}
});
NetDiskViewRightClickMenu.setGlobalRightClickMenu(needDragElement);
},
/**
* 设置window的resize事件监听,来重新设置悬浮按钮的位置
*/
setResizeEventListener() {
/**
* 判断是否是移动端输入框触发的
*/
const isMobileInputKeyboard = ($el: Element | null | undefined) => {
const localName = $el?.localName?.toLowerCase?.();
if (typeof localName === "string" && ["input", "textarea"].includes(localName)) {
// 可能是移动端的输入框弹出的键盘导致的resize
return true;
} else if ($el?.getAttribute?.("contenteditable") === "true" || $el?.closest?.("[contenteditable='true']")) {
// 可能是移动端的输入框弹出的键盘导致的resize
return true;
}
return false;
};
DOMUtils.on(globalThis, "resize", () => {
if (utils.isPhone()) {
const $active = document.activeElement;
const $activeShadowRoot = $active?.shadowRoot?.activeElement;
if (isMobileInputKeyboard($activeShadowRoot ?? $active)) {
return;
}
if (!document.hasFocus()) {
// 页面失焦
return true;
}
}
this.updatePosition(false);
});
},
/**
* 保存悬浮按钮位置
* @param position
*/
savePosition(position: { x?: number; y?: number }) {
if (!CommonUtil.isTopWindow()) {
// 必须在顶部窗口才可以保存位置
return;
}
if (position == null) {
return;
}
if (typeof position.x === "number") {
NetDiskSuspensionConfig.position.suspensionX.value = position.x;
}
if (typeof position.y === "number") {
NetDiskSuspensionConfig.position.suspensionY.value = position.y;
}
NetDiskSuspensionConfig.position.suspensionMaxX.value = NetDiskSuspensionConfig.position.suspensionMaxX.default;
NetDiskSuspensionConfig.position.suspensionMaxY.value = NetDiskSuspensionConfig.position.suspensionMaxY.default;
},
/**
* 更新悬浮按钮位置
* @param isTrusted 是否为用户行为触发,如果为true,保存位置信息
*/
updatePosition(isTrusted: boolean) {
const suspendSize = NetDiskGlobalData.suspension.size.value;
/** 最大的left偏移*/
const MAX_X = DOMUtils.width(window) - suspendSize;
/** 最大的top偏移 */
const MAX_Y = DOMUtils.height(window) - suspendSize;
/** 上次页面的最大left偏移 */
const LAST_MAX_X = NetDiskSuspensionConfig.position.suspensionMaxX.value;
/** 上次页面的最大top偏移 */
const LAST_MAX_Y = NetDiskSuspensionConfig.position.suspensionMaxY.value;
// 把上面的配置的默认值重新设置一下,不能为50
NetDiskSuspensionConfig.position.suspensionMaxX.default = MAX_X;
NetDiskSuspensionConfig.position.suspensionMaxY.default = MAX_Y;
// 用户自己拖动设置的悬浮按钮left偏移
let suspension_X = NetDiskSuspensionConfig.position.suspensionX.value;
// 用户自己拖动设置的悬浮按钮top偏移
let suspension_Y = NetDiskSuspensionConfig.position.suspensionY.value;
// 根据上一次移动的位置,判断上次的最大坐标是否和当前页面的最大坐标一致
// 如果不一致,再根据百分比计算出当前页面的位置
// 然后判断是否超出最大值
// 超出最大值,则使用默认值
if (MAX_X !== LAST_MAX_X) {
// log.warn(`当前页面最大x和上次记录的不一致`);
// 当前页面和上次的页面x坐标不一致
// 计算出百分比
let percent_X = suspension_X / LAST_MAX_X;
// 再计算值
let recalculate_suspension_X = MAX_X * percent_X;
let old_position_X = suspension_X;
suspension_X = recalculate_suspension_X;
if (import.meta.env.DEV) {
log.table([
{
介绍: "上次记录的值",
X: old_position_X,
MAX_X: LAST_MAX_X,
percent: percent_X,
},
{
介绍: "当前页面的值",
X: suspension_X,
MAX_X: MAX_X,
},
]);
}
}
if (MAX_Y !== LAST_MAX_Y) {
// log.warn(`当前页面最大y和上次记录的不一致`);
// 当前页面和上次的页面y坐标不一致
// 计算出百分比
let percent_Y = suspension_Y / LAST_MAX_Y;
// 再计算值
let recalculate_suspension_Y = MAX_Y * percent_Y;
let old_position_Y = suspension_Y;
suspension_Y = recalculate_suspension_Y;
if (import.meta.env.DEV) {
log.table([
{
介绍: "上次记录的值",
Y: old_position_Y,
MAX_Y: LAST_MAX_Y,
percent: percent_Y,
},
{
介绍: "当前页面的值",
Y: suspension_Y,
MAX_Y: MAX_Y,
},
]);
}
}
if (suspension_X > MAX_X) {
// log.warn("left超出最大值,重置为最大值");
// 如果用户设置的left偏移为正的,那么是超出边界,归位设置为最大值
suspension_X = MAX_X;
} else if (suspension_X < 0) {
// log.warn(`left超出最小值,重置为0`);
// 如果用户设置的left偏移为负的,那么是超出边界,归位设置为0
suspension_X = 0;
}
if (suspension_Y > MAX_Y) {
// log.warn("top超出最大值,重置为最大值");
// 如果用户设置的top偏移为正的,那么是超出边界,归位设置为最大值
suspension_Y = MAX_Y;
} else if (suspension_Y < 0) {
// log.warn(`top超出最小值,重置为0`);
// 如果用户设置的top偏移为负的,那么是超出边界,归位设置为0
suspension_Y = 0;
}
if (NetDiskGlobalData.suspension["suspended-button-adsorption-edge"].value) {
// 吸附边缘,只需要该x坐标
// 如果isRight为true,悬浮按钮放到最右边,否则最左边
if (NetDiskSuspensionConfig.position.isRight.value) {
suspension_X = MAX_X;
} else {
suspension_X = 0;
}
}
// 再保存处理的值
if (isTrusted) {
NetDiskSuspension.savePosition({
x: suspension_X,
y: suspension_Y,
});
}
DOMUtils.css(NetDiskView.$inst.suspension.$el.$suspension, {
left: suspension_X + "px",
top: suspension_Y + "px",
});
},
/**
* 更新按钮的z-index值
*/
updateZIndex() {
// 悬浮按钮的z-index
let suspendedZIndex = NetDiskGlobalData.suspension["suspended-z-index"].value;
if (suspendedZIndex <= 0) {
// 自行计算
suspendedZIndex = utils.getMaxValue(40000, utils.getMaxZIndex(10));
}
// 更新z-index
DOMUtils.html(
this.$el.$suspensionZIndexStyle,
/*css*/ `
#whitesevSuspensionId{
z-index: ${suspendedZIndex};
}
`
);
},
/**
* 悬浮按钮背景轮播 效果为淡入淡出
*/
changeBackground() {
if (this.$data.isSwitchBackground) {
return;
}
/**
* 获取随机背景的数组
*/
function getRandBgList() {
let resultList: string[] = [];
NetDiskView.$data.isMatchedNetDiskIconMap.forEach((item) => {
resultList = [...resultList, NetDiskView.$inst.icon.getIcon(item)];
});
return resultList;
}
/**
* 进行切换 淡入淡出
* @param fadeTime 淡入\淡出的时间
* @param currentBackgroundSrc 当前的背景资源
*/
function startSwitch(fadeTime: number, currentBackgroundSrc: string) {
currentList = getRandBgList();
DOMUtils.fadeOut(randBgNode, fadeTime, function () {
currentIndex++;
currentIndex = currentIndex < currentList.length ? currentIndex : 0;
currentBackgroundSrc = currentList[currentIndex];
DOMUtils.css(randBgNode, {
"background-image": `url(${currentBackgroundSrc})`,
});
DOMUtils.fadeIn(randBgNode, fadeTime, function () {
setTimeout(() => {
startSwitch(parseInt(NetDiskGlobalData.suspension["randbg-time"].value.toString()), currentBackgroundSrc);
}, parseInt(NetDiskGlobalData.suspension["randbg-show-time"].value.toString()));
});
});
}
let currentList: string[] = [];
let currentIndex = 0;
currentList = getRandBgList();
let randBgSrc = currentList[currentIndex];
let randBgNode =
NetDiskView.$inst.suspension.$el.$suspension.querySelector(".whitesevSuspension .netdisk")!;
DOMUtils.css(randBgNode, {
"background-image": `url(${randBgSrc})`,
});
if (currentList.length < 2 || NetDiskGlobalData.suspension["randbg-time"].value <= 0) {
// 只有一个的话或淡入/淡出的时间<=0 就不进行背景切换
return;
}
this.$data.isSwitchBackground = true;
startSwitch(parseInt(NetDiskGlobalData.suspension["randbg-time"].value.toString().toString()), randBgSrc);
},
};