mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-30 06:19:45 +08:00
* ⚡️大幅提升UIGF导入速度 (#225) * Initial plan * perf: optimize gacha import with batch transactions and reduced UI delays - Wrap DB inserts in transactions (batches of 500) for mergeUIGF/mergeUIGF4 - Pre-transform all data before batch insert loop - Pass timeout: 0 to showLoading.update in progress callbacks - Remove 1500ms snackbar delay in cleanGachaRecords - Reduce per-item loading update delay in refreshGachaPool Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * fix: increment progress counter per item instead of per batch for accurate progress display Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * Initial plan * feat: calculate window size based on resolution/scaling with baseline check and centering - resizeWindow: add baseline check (1920x1080@150%), clamp to screen bounds - setWindowPos: ensure window fits on screen and always center - App.vue: use setWindowPos instead of manual positioning, center on deep link show - tray.rs: center window when showing from system tray Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * fix: address code review - add zero guard and use setWindowPos consistently Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * refactor: address review feedback - move baseline to setWindowPos, revert tray.rs - tray.rs: reverted, center() removed as redundant - TGWindow.ts: baseline check moved to setWindowPos, resizeWindow restored as fallback - App.vue: needResize=false → setWindowPos, else → center; deep link reverted; handleResizeListen true path unchanged, setWindowPos moved inside else Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * refactor: use needResize judgment condition (targetZoom/scaleFactor/textScale) in setWindowPos Replace the simple curSize > screen.size overflow check with the same condition used by resizeWindow(): targetZoom < 1, which considers scaleFactor and textScale. Falls back to resizeWindow() when below baseline or when targetZoom < 1. Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> * 🚸 调整尺寸判断 * 🚸 处理溢出 * 🚸 优化处理 * 🚸 移除冗余scale处理 * 🎨 CodeStyle --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com> Co-authored-by: BTMuli <bt-muli@outlook.com>
167 lines
5.3 KiB
TypeScript
167 lines
5.3 KiB
TypeScript
/**
|
||
* 窗口创建相关工具函数
|
||
* @since Beta v0.9.8
|
||
*/
|
||
|
||
import type { RenderCard } from "@comp/app/t-postcard.vue";
|
||
import showSnackbar from "@comp/func/snackbar.js";
|
||
import { core, webviewWindow, window as TauriWindow } from "@tauri-apps/api";
|
||
import { invoke } from "@tauri-apps/api/core";
|
||
import { PhysicalPosition, PhysicalSize } from "@tauri-apps/api/dpi";
|
||
import { currentMonitor, WindowOptions } from "@tauri-apps/api/window";
|
||
import { openUrl } from "@tauri-apps/plugin-opener";
|
||
|
||
import TGLogger from "./TGLogger.js";
|
||
|
||
/**
|
||
* 创建TG窗口
|
||
* @since Beta v0.5.0
|
||
* @param url - 窗口地址
|
||
* @param label - 窗口标签
|
||
* @param title - 窗口标题
|
||
* @param width - 窗口宽度
|
||
* @param height - 窗口高度
|
||
* @param resizable - 是否可调整大小
|
||
* @param visible - 是否可见
|
||
* @returns 无返回值
|
||
*/
|
||
export async function createTGWindow(
|
||
url: string,
|
||
label: string,
|
||
title: string,
|
||
width: number,
|
||
height: number,
|
||
resizable: boolean,
|
||
visible: boolean = true,
|
||
): Promise<void> {
|
||
const windowOpt: WindowOptions = {
|
||
title,
|
||
width,
|
||
height,
|
||
resizable,
|
||
visible,
|
||
};
|
||
const window = await TauriWindow.Window.getByLabel(label);
|
||
if (window !== null) await window.destroy();
|
||
await core.invoke("create_window", { label, url, option: windowOpt });
|
||
}
|
||
|
||
/**
|
||
* 打开帖子
|
||
* @since Beta v0.4.2
|
||
* @param item - 帖子内容或ID
|
||
* @param title - 帖子标题
|
||
* @returns 无返回值
|
||
*/
|
||
export async function createPost(
|
||
item: RenderCard | string | number,
|
||
title?: string,
|
||
): Promise<void> {
|
||
let postId: string, postTitle: string;
|
||
if (typeof item === "string" || typeof item === "number") {
|
||
postId = item.toString();
|
||
postTitle = title ? `Post_${postId} ${title}` : `Post_${postId}`;
|
||
} else {
|
||
postId = item.postId.toString();
|
||
postTitle = `Post_${postId} ${item.title}`;
|
||
}
|
||
const postPath = `/post_detail/${postId}`;
|
||
await createTGWindow(postPath, "Sub_window", postTitle, 960, 720, false, false);
|
||
await TGLogger.Info(`[createPost][${postId}] 打开帖子`);
|
||
}
|
||
|
||
/**
|
||
* 打开观测枢
|
||
* @since Beta 0.7.6
|
||
* @param contentId - 观测枢内容ID
|
||
* @returns 无返回值
|
||
*/
|
||
export async function toObcPage(contentId: number): Promise<void> {
|
||
const obcUrl = `https://bbs.mihoyo.com/ys/obc/content/${contentId}/detail?bbs_presentation_style=no_header`;
|
||
await openUrl(obcUrl);
|
||
}
|
||
|
||
/**
|
||
* 获取不同label下的默认窗口大小
|
||
* @since Beta v0.7.2
|
||
* @param label - 窗口标签
|
||
* @returns 物理大小
|
||
*/
|
||
export function getWindowSize(label: string): PhysicalSize {
|
||
switch (label) {
|
||
case "TeyvatGuide":
|
||
return new PhysicalSize(1600, 900);
|
||
case "Sub_window":
|
||
case "Dev_JSON":
|
||
return new PhysicalSize(960, 720);
|
||
default:
|
||
return new PhysicalSize(1280, 720);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 判断窗口位置,确保窗口不超出屏幕并居中
|
||
* @since Beta v0.9.8
|
||
* @remarks 当窗口超出屏幕时回滚到 resizeWindow,此时回正配置默认生效
|
||
* @returns 无返回值
|
||
*/
|
||
export async function setWindowPos(): Promise<void> {
|
||
const screen = await currentMonitor();
|
||
const NAV_BAR_HEIGHT = 28;
|
||
if (screen === null) {
|
||
showSnackbar.error("获取屏幕信息失败!", 3000);
|
||
return;
|
||
}
|
||
const windowCur = webviewWindow.getCurrentWebviewWindow();
|
||
if (await windowCur.isMaximized()) return;
|
||
const designSize = getWindowSize(windowCur.label);
|
||
const screenScale = screen.scaleFactor;
|
||
const targetWidth = Math.round(designSize.width * screenScale);
|
||
const targetHeight = Math.round(designSize.height * screenScale);
|
||
const cpWidth = screen.size.width - NAV_BAR_HEIGHT * screenScale;
|
||
const cpHeight = screen.size.height - NAV_BAR_HEIGHT * screenScale;
|
||
if (targetWidth > cpWidth && targetHeight > cpHeight) {
|
||
await resizeWindow();
|
||
await windowCur.center();
|
||
} else if (targetHeight > cpHeight) {
|
||
const left = (screen.size.width - targetWidth) / 2;
|
||
await windowCur.setSize(new PhysicalSize(targetWidth, targetHeight));
|
||
await windowCur.setPosition(new PhysicalPosition(left, 24));
|
||
} else if (targetWidth > screen.size.width) {
|
||
const top = (screen.size.height - targetHeight) / 2;
|
||
await windowCur.setSize(new PhysicalSize(targetWidth, targetHeight));
|
||
await windowCur.setPosition(new PhysicalPosition(24, top));
|
||
} else {
|
||
await windowCur.setSize(new PhysicalSize(targetWidth, targetHeight));
|
||
await windowCur.center();
|
||
}
|
||
await windowCur.setZoom(1);
|
||
}
|
||
|
||
/**
|
||
* 窗口适配
|
||
* @since Beta v0.9.6
|
||
* @returns 无返回值
|
||
*/
|
||
export async function resizeWindow(): Promise<void> {
|
||
const screen = await currentMonitor();
|
||
if (screen === null) {
|
||
showSnackbar.error("获取屏幕信息失败!", 3000);
|
||
return;
|
||
}
|
||
const windowCur = webviewWindow.getCurrentWebviewWindow();
|
||
const textScale = await invoke<number>("read_text_scale");
|
||
if (await windowCur.isMaximized()) return;
|
||
const designSize = getWindowSize(windowCur.label);
|
||
const widthScale = screen.size.width / 1920;
|
||
const heightScale = screen.size.height / 1080;
|
||
const targetWidth = Math.round(designSize.width * widthScale);
|
||
const targetHeight = Math.round(designSize.height * heightScale);
|
||
if (await windowCur.isMaximized()) {
|
||
await windowCur.unmaximize();
|
||
}
|
||
await windowCur.setSize(new PhysicalSize(targetWidth, targetHeight));
|
||
const targetZoom = Math.min(widthScale, heightScale) / (screen.scaleFactor * textScale);
|
||
await windowCur.setZoom(targetZoom);
|
||
}
|