Track bundled vendor runtime sources
This commit is contained in:
21
vendor/aigcpanel/electron/mapi/app/icons.ts
vendored
Normal file
21
vendor/aigcpanel/electron/mapi/app/icons.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
export const icons = {
|
||||
success:
|
||||
'<svg t="1733817409678" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1488" width="1024" height="1024"><path d="M512 832c-176.448 0-320-143.552-320-320S335.552 192 512 192s320 143.552 320 320-143.552 320-320 320m0-704C300.256 128 128 300.256 128 512s172.256 384 384 384 384-172.256 384-384S723.744 128 512 128" fill="#FFF" p-id="1489"></path><path d="M619.072 429.088l-151.744 165.888-62.112-69.6a32 32 0 1 0-47.744 42.624l85.696 96a32 32 0 0 0 23.68 10.688h0.192c8.96 0 17.536-3.776 23.616-10.4l175.648-192a32 32 0 0 0-47.232-43.2" fill="#FFF" p-id="1490"></path></svg>',
|
||||
error: '<svg t="1733817396560" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1326" width="1024" height="1024"><path d="M512 128C300.8 128 128 300.8 128 512s172.8 384 384 384 384-172.8 384-384S723.2 128 512 128zM512 832c-179.2 0-320-140.8-320-320s140.8-320 320-320 320 140.8 320 320S691.2 832 512 832z" fill="#FFF" p-id="1327"></path><path d="M672 352c-12.8-12.8-32-12.8-44.8 0L512 467.2 396.8 352C384 339.2 364.8 339.2 352 352S339.2 384 352 396.8L467.2 512 352 627.2c-12.8 12.8-12.8 32 0 44.8s32 12.8 44.8 0L512 556.8l115.2 115.2c12.8 12.8 32 12.8 44.8 0s12.8-32 0-44.8L556.8 512l115.2-115.2C684.8 384 684.8 364.8 672 352z" fill="#FFF" p-id="1328"></path></svg>',
|
||||
info: '<svg t="1733992721464" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1357" width="1024" height="1024"><path d="M512 898.71874973C299.30468777 898.71874973 125.28125027 724.69531223 125.28125027 512S299.30468777 125.28125027 512 125.28125027s386.71874973 174.0234375 386.71874973 386.71874973-174.0234375 386.71874973-386.71874973 386.71874973z m0-696.09375c-170.15625027 0-309.37500027 139.21875-309.37500027 309.37500027 0 170.15625027 139.21875 309.37500027 309.37500027 309.37500027 170.15625027 0 309.37500027-139.21875 309.37500027-309.37500027 0-170.15625027-139.21875-309.37500027-309.37500027-309.37500027z" fill="#FFFFFF" p-id="1358"></path><path d="M512 746.59765652a37.96875 37.96875 0 0 1-38.67187473-38.67187554v-221.6953125c0-21.9375 16.76953125-38.67187473 38.67187473-38.67187473 21.90234348 0 38.67187473 16.73437473 38.67187473 38.67187473v221.6953125c0 21.9375-16.76953125 38.67187473-38.67187473 38.67187554zM512 390.81640625a37.96875 37.96875 0 0 1-38.67187473-38.67187473V316.07421902c0-21.9375 16.76953125-38.67187473 38.67187473-38.67187554 21.90234348 0 38.67187473 16.73437473 38.67187473 38.67187554v36.0703125c0 21.9375-18.03515625 38.67187473-38.67187473 38.67187473z" fill="#FFFFFF" p-id="1359"></path></svg>',
|
||||
loading: `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
<rect fill="#FFFFFF" x="21.5" y="21.5" width="25" height="25" rx="3" ry="3">
|
||||
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-1.375s" repeatCount="indefinite"></animate>
|
||||
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-1s" repeatCount="indefinite"></animate>
|
||||
</rect>
|
||||
<rect fill="#FFFFFF" x="21.5" y="53.5" width="25" height="25" rx="3" ry="3">
|
||||
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.875s" repeatCount="indefinite"></animate>
|
||||
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.5s" repeatCount="indefinite"></animate>
|
||||
</rect>
|
||||
<rect fill="#FFFFFF" x="53.5" y="42.919" width="25" height="25" rx="3" ry="3">
|
||||
<animate attributeName="x" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="-0.375s" repeatCount="indefinite"></animate>
|
||||
<animate attributeName="y" calcMode="linear" values="21.5;53.5;53.5;53.5;53.5;21.5;21.5;21.5;21.5" keyTimes="0;0.083;0.25;0.333;0.5;0.583;0.75;0.833;1" dur="1.5" begin="0s" repeatCount="indefinite"></animate>
|
||||
</rect>
|
||||
</svg>`,
|
||||
};
|
||||
362
vendor/aigcpanel/electron/mapi/app/index.ts
vendored
Normal file
362
vendor/aigcpanel/electron/mapi/app/index.ts
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
import iconv from "iconv-lite";
|
||||
import { exec as _exec, spawn } from "node:child_process";
|
||||
import net from "node:net";
|
||||
import util from "node:util";
|
||||
import { AppConfig } from "../../../src/config";
|
||||
import {
|
||||
extraResolveBin,
|
||||
isLinux,
|
||||
isMac,
|
||||
isWin,
|
||||
platformArch,
|
||||
platformName,
|
||||
platformUUID,
|
||||
platformVersion,
|
||||
} from "../../lib/env";
|
||||
import { IconvUtil, ShellUtil, StrUtil } from "../../lib/util";
|
||||
import { Log } from "../log/index";
|
||||
|
||||
const exec = util.promisify(_exec);
|
||||
|
||||
const outputStringConvert = (outputEncoding: "utf8" | "cp936", data: any) => {
|
||||
if (!data) {
|
||||
return "";
|
||||
}
|
||||
if (outputEncoding === "utf8") {
|
||||
return data.toString();
|
||||
}
|
||||
let dataEncoding = "binary";
|
||||
if (Buffer.isBuffer(data)) {
|
||||
dataEncoding = IconvUtil.detect(data as any);
|
||||
if ("UTF-8" === dataEncoding) {
|
||||
return data.toString("utf8");
|
||||
}
|
||||
}
|
||||
// dataEncoding UTF-8 cp936
|
||||
// dataEncoding ISO-8859-1 cp936
|
||||
// console.log('dataEncoding', dataEncoding, outputEncoding)
|
||||
return iconv.decode(Buffer.from(data, dataEncoding as any), outputEncoding);
|
||||
};
|
||||
|
||||
const shell = async (
|
||||
command: string,
|
||||
option?: {
|
||||
cwd?: string;
|
||||
outputEncoding?: string;
|
||||
shell?: boolean;
|
||||
},
|
||||
) => {
|
||||
option = Object.assign(
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
outputEncoding: isWin ? "cp936" : "utf8",
|
||||
shell: true,
|
||||
},
|
||||
option,
|
||||
);
|
||||
const result = await exec(command, {
|
||||
env: { ...process.env },
|
||||
shell: option.shell,
|
||||
encoding: "binary",
|
||||
cwd: option["cwd"],
|
||||
} as any);
|
||||
return {
|
||||
stdout: outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
result.stdout,
|
||||
),
|
||||
stderr: outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
result.stderr,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const spawnShell = async (
|
||||
command: string | string[],
|
||||
option: {
|
||||
stdout?: (data: string, process: any) => void;
|
||||
stderr?: (data: string, process: any) => void;
|
||||
success?: (process: any) => void;
|
||||
error?: (msg: string, exitCode: number, process: any) => void;
|
||||
cwd?: string;
|
||||
outputEncoding?: string;
|
||||
env?: Record<string, any>;
|
||||
shell?: boolean;
|
||||
} | null = null,
|
||||
): Promise<{
|
||||
stop: () => void;
|
||||
send: (data: any) => void;
|
||||
result: () => Promise<string>;
|
||||
}> => {
|
||||
option = Object.assign(
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
outputEncoding: isWin ? "cp936" : "utf8",
|
||||
env: {},
|
||||
shell: true,
|
||||
},
|
||||
option,
|
||||
);
|
||||
let commandEntry = "",
|
||||
args = [];
|
||||
if (Array.isArray(command)) {
|
||||
commandEntry = command[0];
|
||||
args = command.slice(1);
|
||||
} else {
|
||||
args = ShellUtil.parseCommandArgs(command);
|
||||
commandEntry = args.shift() as string;
|
||||
}
|
||||
Log.info("App.spawnShell", {
|
||||
commandEntry,
|
||||
args,
|
||||
option: {
|
||||
cwd: option["cwd"],
|
||||
outputEncoding: option["outputEncoding"],
|
||||
},
|
||||
});
|
||||
const spawnProcess = spawn(commandEntry, args, {
|
||||
env: { ...process.env, ...option.env },
|
||||
cwd: option["cwd"],
|
||||
shell: option.shell,
|
||||
encoding: "binary",
|
||||
} as any);
|
||||
let end = false;
|
||||
let isSuccess = false;
|
||||
let exitCode = -1;
|
||||
const stdoutList: string[] = [];
|
||||
const stderrList: string[] = [];
|
||||
spawnProcess.stdout?.on("data", (data) => {
|
||||
// console.log('App.spawnShell.stdout', data)
|
||||
let dataString = outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
data,
|
||||
);
|
||||
Log.info("App.spawnShell.stdout", dataString);
|
||||
stdoutList.push(dataString);
|
||||
option.stdout?.(dataString, spawnProcess);
|
||||
});
|
||||
spawnProcess.stderr?.on("data", (data) => {
|
||||
// console.log('App.spawnShell.stderr', data)
|
||||
let dataString = outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
data,
|
||||
);
|
||||
Log.info("App.spawnShell.stderr", dataString);
|
||||
stderrList.push(dataString);
|
||||
option.stderr?.(dataString, spawnProcess);
|
||||
});
|
||||
spawnProcess.on("exit", (code, signal) => {
|
||||
// console.log('App.spawnShell.exit', code)
|
||||
Log.info("App.spawnShell.exit", { code, signal });
|
||||
exitCode = code;
|
||||
if (isWin) {
|
||||
if (0 === code || 1 === code) {
|
||||
isSuccess = true;
|
||||
}
|
||||
} else {
|
||||
if (null === code || 0 === code) {
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
if (isSuccess) {
|
||||
option.success?.(spawnProcess);
|
||||
} else {
|
||||
option.error?.(
|
||||
`command ${command} failed with code ${code}`,
|
||||
exitCode,
|
||||
spawnProcess,
|
||||
);
|
||||
}
|
||||
end = true;
|
||||
});
|
||||
spawnProcess.on("error", (err) => {
|
||||
// console.log('App.spawnShell.error', err)
|
||||
Log.info("App.spawnShell.error", err);
|
||||
option.error?.(err.toString(), -1, spawnProcess);
|
||||
end = true;
|
||||
});
|
||||
return {
|
||||
stop: () => {
|
||||
Log.info("App.spawnShell.stop");
|
||||
if (isWin) {
|
||||
_exec(
|
||||
`taskkill /pid ${spawnProcess.pid} /T /F`,
|
||||
{
|
||||
encoding: "binary",
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (stdout) {
|
||||
stdout = outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
stdout,
|
||||
);
|
||||
}
|
||||
if (stderr) {
|
||||
stderr = outputStringConvert(
|
||||
option.outputEncoding as any,
|
||||
stderr,
|
||||
);
|
||||
}
|
||||
Log.info(
|
||||
"App.spawnShell.stop.taskkill",
|
||||
JSON.parse(JSON.stringify({ err, stdout, stderr })),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
spawnProcess.kill("SIGINT");
|
||||
}
|
||||
},
|
||||
send: (data) => {
|
||||
Log.info("App.spawnShell.send", data);
|
||||
spawnProcess.stdin.write(data);
|
||||
},
|
||||
result: async (): Promise<string> => {
|
||||
if (end) {
|
||||
return stdoutList.join("") + stderrList.join("");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const watchEnd = () => {
|
||||
setTimeout(() => {
|
||||
if (!end) {
|
||||
watchEnd();
|
||||
return;
|
||||
}
|
||||
if (isSuccess) {
|
||||
resolve(stdoutList.join("") + stderrList.join(""));
|
||||
} else {
|
||||
reject(
|
||||
[
|
||||
`command ${command} failed with code ${exitCode} : `,
|
||||
stdoutList.join(""),
|
||||
stderrList.join(""),
|
||||
].join(""),
|
||||
);
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
watchEnd();
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const spawnBinary = async (
|
||||
binary: string,
|
||||
args: string[],
|
||||
option: {
|
||||
stdout?: (data: string, process: any) => void;
|
||||
stderr?: (data: string, process: any) => void;
|
||||
success?: (process: any) => void;
|
||||
error?: (msg: string, exitCode: number, process: any) => void;
|
||||
cwd?: string;
|
||||
outputEncoding?: string;
|
||||
env?: Record<string, any>;
|
||||
shell?: boolean;
|
||||
} | null = null,
|
||||
): Promise<string> => {
|
||||
args.unshift(extraResolveBin(binary));
|
||||
const res = await Apps.spawnShell(args, {
|
||||
...(option || {}),
|
||||
shell: false,
|
||||
});
|
||||
return await res.result();
|
||||
};
|
||||
|
||||
const availablePortLock: {
|
||||
[port: number]: {
|
||||
lockKey: string;
|
||||
lockTime: number;
|
||||
};
|
||||
} = {};
|
||||
|
||||
/**
|
||||
* 获取一个可用的端口
|
||||
* @param start 开始的端口
|
||||
* @param lockKey 锁定的key,避免其他进程获取,默认会创建一个随机的key
|
||||
* @param lockTime 锁定时间,避免在本次获取后未启动服务导致其他进程重复获取
|
||||
*/
|
||||
const availablePort = async (
|
||||
start: number,
|
||||
lockKey?: string,
|
||||
lockTime?: number,
|
||||
): Promise<number> => {
|
||||
lockKey = lockKey || StrUtil.randomString(8);
|
||||
lockTime = lockTime || 60;
|
||||
// expire lock
|
||||
const now = Date.now();
|
||||
for (const port in availablePortLock) {
|
||||
const lockInfo = availablePortLock[port];
|
||||
if (lockInfo.lockTime < now) {
|
||||
delete availablePortLock[port];
|
||||
}
|
||||
}
|
||||
for (let i = start; i < 65535; i++) {
|
||||
const available = await isPortAvailable(i, "0.0.0.0");
|
||||
const availableLocal = await isPortAvailable(i, "127.0.0.1");
|
||||
// console.log('isPortAvailable', i, available, availableLocal)
|
||||
if (available && availableLocal) {
|
||||
const lockInfo = availablePortLock[i];
|
||||
if (lockInfo) {
|
||||
if (lockInfo.lockKey === lockKey) {
|
||||
return i;
|
||||
} else {
|
||||
// other lockKey lock the port
|
||||
continue;
|
||||
}
|
||||
}
|
||||
availablePortLock[i] = {
|
||||
lockKey,
|
||||
lockTime: Date.now() + lockTime * 1000,
|
||||
};
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new Error("no available port");
|
||||
};
|
||||
|
||||
const isPortAvailable = async (
|
||||
port: number,
|
||||
host?: string,
|
||||
): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
const server = net.createServer();
|
||||
server.listen(port, host);
|
||||
server.on("listening", () => {
|
||||
server.close();
|
||||
resolve(true);
|
||||
});
|
||||
server.on("error", () => {
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const fixExecutable = async (executable: string) => {
|
||||
if (isMac || isLinux) {
|
||||
// chmod +x executable
|
||||
await shell(`chmod +x "${executable}"`);
|
||||
}
|
||||
};
|
||||
|
||||
const getUserAgent = () => {
|
||||
let param = [];
|
||||
param.push(`AppOpen/${AppConfig.name}/${AppConfig.version}`);
|
||||
param.push(
|
||||
`Platform/${platformName()}/${platformArch()}/${platformVersion()}/${platformUUID()}`,
|
||||
);
|
||||
return param.join(" ");
|
||||
};
|
||||
|
||||
export const Apps = {
|
||||
shell,
|
||||
spawnShell,
|
||||
spawnBinary,
|
||||
availablePort,
|
||||
isPortAvailable,
|
||||
fixExecutable,
|
||||
getUserAgent,
|
||||
};
|
||||
|
||||
export default Apps;
|
||||
102
vendor/aigcpanel/electron/mapi/app/lib/position.ts
vendored
Normal file
102
vendor/aigcpanel/electron/mapi/app/lib/position.ts
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
import { screen } from "electron";
|
||||
|
||||
type PositionCache = {
|
||||
x: 0;
|
||||
y: 0;
|
||||
screenWidth: 0;
|
||||
screenHeight: 0;
|
||||
id: -1;
|
||||
};
|
||||
|
||||
export const AppPosition = {
|
||||
caches: {} as Record<string, PositionCache>,
|
||||
getCache(name: string): PositionCache {
|
||||
if (!this.caches[name]) {
|
||||
this.caches[name] = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
screenWidth: 0,
|
||||
screenHeight: 0,
|
||||
id: -1,
|
||||
};
|
||||
}
|
||||
return this.caches[name];
|
||||
},
|
||||
get(
|
||||
name: string,
|
||||
calculator?: (
|
||||
screenX: number,
|
||||
screenY: number,
|
||||
screenWidth: number,
|
||||
screenHeight: number,
|
||||
) => {
|
||||
x: number;
|
||||
y: number;
|
||||
},
|
||||
): {
|
||||
x: number;
|
||||
y: number;
|
||||
} {
|
||||
const cache = this.getCache(name);
|
||||
const { x, y } = screen.getCursorScreenPoint();
|
||||
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
|
||||
if (cache.id !== currentDisplay.id) {
|
||||
cache.id = currentDisplay.id;
|
||||
cache.screenWidth = currentDisplay.workArea.width;
|
||||
cache.screenHeight = currentDisplay.workArea.height;
|
||||
if (!calculator) {
|
||||
calculator = (
|
||||
screenX: number,
|
||||
screenY: number,
|
||||
screenWidth: number,
|
||||
screenHeight: number,
|
||||
) => {
|
||||
// console.log('calculator', {screenX, screenY, screenWidth, screenHeight});
|
||||
return {
|
||||
x: screenX + screenWidth / 10,
|
||||
y: screenY + screenHeight / 10,
|
||||
};
|
||||
};
|
||||
}
|
||||
const res = calculator(
|
||||
currentDisplay.workArea.x,
|
||||
currentDisplay.workArea.y,
|
||||
cache.screenWidth,
|
||||
cache.screenHeight,
|
||||
);
|
||||
cache.x = parseInt(String(res.x));
|
||||
cache.y = parseInt(String(res.y));
|
||||
}
|
||||
return {
|
||||
x: cache.x,
|
||||
y: cache.y,
|
||||
};
|
||||
},
|
||||
set(name: string, x: number, y: number): void {
|
||||
const cache = this.getCache(name);
|
||||
cache.x = x;
|
||||
cache.y = y;
|
||||
},
|
||||
getContextMenuPosition(
|
||||
boxWidth: number,
|
||||
boxHeight: number,
|
||||
): {
|
||||
x: number;
|
||||
y: number;
|
||||
} {
|
||||
const { x, y } = screen.getCursorScreenPoint();
|
||||
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
|
||||
let resultX = x;
|
||||
let resultY = y;
|
||||
if (currentDisplay.workArea.width - x < boxWidth) {
|
||||
resultX = currentDisplay.workArea.width - boxWidth;
|
||||
}
|
||||
if (currentDisplay.workArea.height - y < boxHeight) {
|
||||
resultY = currentDisplay.workArea.height - boxHeight;
|
||||
}
|
||||
return {
|
||||
x: resultX,
|
||||
y: resultY,
|
||||
};
|
||||
},
|
||||
};
|
||||
175
vendor/aigcpanel/electron/mapi/app/loading.ts
vendored
Normal file
175
vendor/aigcpanel/electron/mapi/app/loading.ts
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
import { BrowserWindow } from "electron";
|
||||
import { AppsMain } from "./main";
|
||||
import { icons } from "./icons";
|
||||
|
||||
export const makeLoading = (
|
||||
msg: string,
|
||||
options?: {
|
||||
timeout?: number;
|
||||
percentAuto?: boolean;
|
||||
percentTotalSeconds?: number;
|
||||
},
|
||||
): {
|
||||
close: () => void;
|
||||
percent: (value: number) => void;
|
||||
} => {
|
||||
options = Object.assign(
|
||||
{
|
||||
percentAuto: false,
|
||||
percentTotalSeconds: 30,
|
||||
timeout: 0,
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
if (options.timeout === 0) {
|
||||
options.timeout = 60 * 10 * 1000;
|
||||
}
|
||||
// console.log('options', options)
|
||||
|
||||
const display = AppsMain.getCurrentScreenDisplay();
|
||||
// console.log('xxxx', primaryDisplay);
|
||||
const width = display.workArea.width;
|
||||
const height = 60;
|
||||
const icon = icons.loading;
|
||||
|
||||
const win = new BrowserWindow({
|
||||
height,
|
||||
width,
|
||||
x: 0,
|
||||
y: 0,
|
||||
modal: false,
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
center: false,
|
||||
transparent: true,
|
||||
hasShadow: false,
|
||||
show: false,
|
||||
focusable: false,
|
||||
skipTaskbar: true,
|
||||
});
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html,body{
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.message-view {
|
||||
height: 100vh;
|
||||
display:flex;
|
||||
text-align:center;
|
||||
padding:0 10px;
|
||||
position:relative;
|
||||
}
|
||||
.message-view #message{
|
||||
margin: auto;
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
line-height: 30px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.message-view #message .icon{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display:inline-block;
|
||||
margin-right: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.message-view #percent{
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
height: 5px;
|
||||
border-radius: 5px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
overflow: hidden;
|
||||
display:none;
|
||||
}
|
||||
.message-view #percent .value{
|
||||
border-radius: 5px;
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="message-view">
|
||||
<div id="message">${icon}${msg}</div>
|
||||
<div id="percent">
|
||||
<div class="value"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const encodedHTML = encodeURIComponent(htmlContent);
|
||||
let percentAutoTimer = null;
|
||||
win.loadURL(`data:text/html;charset=UTF-8,${encodedHTML}`);
|
||||
win.on("ready-to-show", async () => {
|
||||
const width = Math.ceil(
|
||||
await win.webContents.executeJavaScript(`(()=>{
|
||||
const message = document.getElementById('message');
|
||||
const width = message.scrollWidth;
|
||||
return width;
|
||||
})()`),
|
||||
);
|
||||
win.setSize(width + 20, height);
|
||||
const x =
|
||||
display.workArea.x + display.workArea.width / 2 - (width + 20) / 2;
|
||||
const y = display.workArea.y + (display.workArea.height * 1) / 4;
|
||||
win.setPosition(Math.floor(x), Math.floor(y));
|
||||
win.show();
|
||||
if (options.percentAuto) {
|
||||
let percent = 0;
|
||||
percentAutoTimer = setInterval(
|
||||
() => {
|
||||
percent += 0.01;
|
||||
if (percent >= 1) {
|
||||
clearInterval(percentAutoTimer);
|
||||
return;
|
||||
}
|
||||
controller.percent(percent);
|
||||
},
|
||||
(options.percentTotalSeconds * 1000) / 100,
|
||||
);
|
||||
}
|
||||
// win.webContents.openDevTools({
|
||||
// mode: 'detach'
|
||||
// })
|
||||
});
|
||||
const winCloseTimer = setTimeout(() => {
|
||||
win.close();
|
||||
clearTimeout(winCloseTimer);
|
||||
}, options.timeout);
|
||||
const controller = {
|
||||
close: () => {
|
||||
win.close();
|
||||
clearTimeout(winCloseTimer);
|
||||
if (percentAutoTimer) {
|
||||
clearInterval(percentAutoTimer);
|
||||
}
|
||||
},
|
||||
percent: (value: number) => {
|
||||
const percent = 100 * value;
|
||||
win.webContents.executeJavaScript(`(()=>{
|
||||
const percent = document.querySelector('#percent');
|
||||
const percentValue = document.querySelector('#percent .value');
|
||||
percent.style.display = 'block';
|
||||
percentValue.style.width = '${percent}%';
|
||||
})()`);
|
||||
},
|
||||
};
|
||||
return controller;
|
||||
};
|
||||
454
vendor/aigcpanel/electron/mapi/app/main.ts
vendored
Normal file
454
vendor/aigcpanel/electron/mapi/app/main.ts
vendored
Normal file
@@ -0,0 +1,454 @@
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
clipboard,
|
||||
ipcMain,
|
||||
nativeImage,
|
||||
nativeTheme,
|
||||
screen,
|
||||
shell,
|
||||
} from "electron";
|
||||
import { AppConfig } from "../../../src/config";
|
||||
import { CommonConfig } from "../../config/common";
|
||||
import { WindowConfig } from "../../config/window";
|
||||
import {
|
||||
isDev,
|
||||
isMac,
|
||||
platformArch,
|
||||
platformName,
|
||||
platformUUID,
|
||||
platformVersion,
|
||||
} from "../../lib/env";
|
||||
import { preloadDefault, rendererDistPath } from "../../lib/env-main";
|
||||
import { Page } from "../../page";
|
||||
import { ConfigMain } from "../config/main";
|
||||
import { AppRuntime } from "../env";
|
||||
import { Events } from "../event/main";
|
||||
import { Files } from "../file/main";
|
||||
import Apps from "./index";
|
||||
import { AppPosition } from "./lib/position";
|
||||
import { makeLoading } from "./loading";
|
||||
import { SetupMain } from "./setup";
|
||||
import { makeToast } from "./toast";
|
||||
|
||||
const getWindowByName = (name?: string) => {
|
||||
if (!name || "main" === name) {
|
||||
return AppRuntime.mainWindow;
|
||||
}
|
||||
return AppRuntime.windows[name];
|
||||
};
|
||||
|
||||
const getCurrentWindow = (window, e) => {
|
||||
let originWindow = BrowserWindow.fromWebContents(e.sender);
|
||||
// if (originWindow !== window) originWindow = detachInstance.getWindow();
|
||||
return originWindow;
|
||||
};
|
||||
|
||||
const quit = () => {
|
||||
// @ts-ignore
|
||||
app.quitForce = true;
|
||||
app.quit();
|
||||
};
|
||||
|
||||
ipcMain.handle("app:quit", () => {
|
||||
quit();
|
||||
});
|
||||
|
||||
const restart = () => {
|
||||
app.relaunch();
|
||||
};
|
||||
|
||||
ipcMain.handle("app:restart", () => {
|
||||
restart();
|
||||
});
|
||||
|
||||
const windowMin = (name?: string) => {
|
||||
getWindowByName(name)?.minimize();
|
||||
};
|
||||
|
||||
const windowMax = (name?: string) => {
|
||||
const win = getWindowByName(name);
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
if (win.isFullScreen()) {
|
||||
win.setFullScreen(false);
|
||||
win.unmaximize();
|
||||
win.center();
|
||||
} else if (win.isMaximized()) {
|
||||
win.unmaximize();
|
||||
win.center();
|
||||
} else {
|
||||
win.setMinimumSize(WindowConfig.minWidth, WindowConfig.minHeight);
|
||||
win.maximize();
|
||||
}
|
||||
};
|
||||
|
||||
const windowSetSize = (
|
||||
name: string | null,
|
||||
width: number,
|
||||
height: number,
|
||||
option?: {
|
||||
includeMinimumSize: boolean;
|
||||
center: boolean;
|
||||
},
|
||||
) => {
|
||||
width = parseInt(String(width));
|
||||
height = parseInt(String(height));
|
||||
// console.log('windowSetSize', name, width, height, option)
|
||||
const win = getWindowByName(name);
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
option = Object.assign(
|
||||
{
|
||||
includeMinimumSize: true,
|
||||
center: true,
|
||||
},
|
||||
option,
|
||||
);
|
||||
if (option.includeMinimumSize) {
|
||||
win.setMinimumSize(width, height);
|
||||
}
|
||||
win.setSize(width, height);
|
||||
if (option.center) {
|
||||
win.center();
|
||||
}
|
||||
};
|
||||
|
||||
ipcMain.handle("app:openExternal", (event, url: string) => {
|
||||
return shell.openExternal(url);
|
||||
});
|
||||
ipcMain.handle("app:openPath", (event, url: string) => {
|
||||
return shell.openPath(url);
|
||||
});
|
||||
ipcMain.handle("app:showItemInFolder", (event, url: string) => {
|
||||
return shell.showItemInFolder(url);
|
||||
});
|
||||
|
||||
ipcMain.handle("app:getPreload", (event) => {
|
||||
let preload = preloadDefault;
|
||||
if (!preload.startsWith("file://")) {
|
||||
preload = `file://${preload}`;
|
||||
}
|
||||
return preload;
|
||||
});
|
||||
|
||||
ipcMain.handle("window:min", (event, name: string) => {
|
||||
windowMin(name);
|
||||
});
|
||||
ipcMain.handle("window:max", (event, name: string) => {
|
||||
windowMax(name);
|
||||
});
|
||||
ipcMain.handle(
|
||||
"window:setSize",
|
||||
(
|
||||
event,
|
||||
name: string | null,
|
||||
width: number,
|
||||
height: number,
|
||||
option?: {
|
||||
includeMinimumSize: boolean;
|
||||
center: boolean;
|
||||
},
|
||||
) => {
|
||||
windowSetSize(name, width, height, option);
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.handle("window:close", (event, name: string) => {
|
||||
getWindowByName(name)?.close();
|
||||
});
|
||||
|
||||
const windowOpen = async (
|
||||
name: string,
|
||||
option?: {
|
||||
singleton?: boolean;
|
||||
parent?: BrowserWindow;
|
||||
[key: string]: any;
|
||||
},
|
||||
) => {
|
||||
name = name || "main";
|
||||
return Page.open(name, option);
|
||||
};
|
||||
|
||||
ipcMain.handle("window:open", (event, name: string, option: any) => {
|
||||
return windowOpen(name, option);
|
||||
});
|
||||
|
||||
ipcMain.handle("window:hide", (event, name: string) => {
|
||||
getWindowByName(name)?.hide();
|
||||
if (isMac) {
|
||||
app.dock.hide();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
"window:move",
|
||||
(
|
||||
event,
|
||||
name: string | null,
|
||||
data: {
|
||||
mouseX: number;
|
||||
mouseY: number;
|
||||
width: number;
|
||||
height: number;
|
||||
},
|
||||
) => {
|
||||
const { x, y } = screen.getCursorScreenPoint();
|
||||
const originWindow = getWindowByName(name);
|
||||
if (!originWindow) return;
|
||||
originWindow.setBounds({
|
||||
x: x - data.mouseX,
|
||||
y: y - data.mouseY,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
});
|
||||
AppPosition.set(name, x - data.mouseX, y - data.mouseY);
|
||||
},
|
||||
);
|
||||
|
||||
const getClipboardText = () => {
|
||||
return clipboard.readText("clipboard");
|
||||
};
|
||||
|
||||
ipcMain.handle("app:getClipboardText", (event) => {
|
||||
return getClipboardText();
|
||||
});
|
||||
|
||||
const setClipboardText = (text: string) => {
|
||||
clipboard.writeText(text, "clipboard");
|
||||
};
|
||||
|
||||
ipcMain.handle("app:setClipboardText", (event, text: string) => {
|
||||
setClipboardText(text);
|
||||
});
|
||||
|
||||
const getClipboardImage = () => {
|
||||
const image = clipboard.readImage("clipboard");
|
||||
return image.isEmpty() ? "" : image.toDataURL();
|
||||
};
|
||||
|
||||
ipcMain.handle("app:getClipboardImage", (event) => {
|
||||
return getClipboardImage();
|
||||
});
|
||||
|
||||
const setClipboardImage = (image: string) => {
|
||||
const img = nativeImage.createFromDataURL(image);
|
||||
clipboard.writeImage(img, "clipboard");
|
||||
};
|
||||
|
||||
ipcMain.handle("app:setClipboardImage", (event, image: string) => {
|
||||
setClipboardImage(image);
|
||||
});
|
||||
|
||||
const isDarkMode = () => {
|
||||
if (!CommonConfig.darkModeEnable) {
|
||||
return false;
|
||||
}
|
||||
return nativeTheme.shouldUseDarkColors;
|
||||
};
|
||||
|
||||
const shouldDarkMode = async () => {
|
||||
if (!CommonConfig.darkModeEnable) {
|
||||
return false;
|
||||
}
|
||||
const darkMode = (await ConfigMain.get("darkMode")) || "auto";
|
||||
if ("dark" === darkMode) {
|
||||
return true;
|
||||
} else if ("light" === darkMode) {
|
||||
return false;
|
||||
} else if ("auto" === darkMode) {
|
||||
return isDarkMode();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const defaultDarkModeBackgroundColor = async () => {
|
||||
if (await shouldDarkMode()) {
|
||||
return "#17171A";
|
||||
}
|
||||
return "#FFFFFF";
|
||||
};
|
||||
|
||||
nativeTheme.on("updated", () => {
|
||||
Events.broadcast("DarkModeChange", { isDarkMode: isDarkMode() });
|
||||
AppsMain.defaultDarkModeBackgroundColor().then((color) => {
|
||||
AppRuntime.mainWindow.setBackgroundColor(color);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle("app:isDarkMode", () => {
|
||||
return isDarkMode();
|
||||
});
|
||||
|
||||
const getCurrentScreenDisplay = () => {
|
||||
const screenPoint = screen.getCursorScreenPoint();
|
||||
const display = screen.getDisplayNearestPoint(screenPoint);
|
||||
return {
|
||||
bounds: display.bounds,
|
||||
workArea: display.workArea,
|
||||
};
|
||||
};
|
||||
|
||||
const calcPositionInCurrentDisplay = (
|
||||
position:
|
||||
| "center"
|
||||
| "left-top"
|
||||
| "right-top"
|
||||
| "left-bottom"
|
||||
| "right-bottom",
|
||||
width: number,
|
||||
height: number,
|
||||
) => {
|
||||
const { bounds, workArea } = getCurrentScreenDisplay();
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
switch (position) {
|
||||
case "center":
|
||||
x = workArea.x + (workArea.width - width) / 2;
|
||||
y = workArea.y + (workArea.height - height) / 2;
|
||||
break;
|
||||
case "left-top":
|
||||
x = workArea.x;
|
||||
y = workArea.y;
|
||||
break;
|
||||
case "right-top":
|
||||
x = workArea.x + workArea.width - width;
|
||||
y = workArea.y;
|
||||
break;
|
||||
case "left-bottom":
|
||||
x = workArea.x;
|
||||
y = workArea.y + workArea.height - height;
|
||||
break;
|
||||
case "right-bottom":
|
||||
x = workArea.x + workArea.width - width;
|
||||
y = workArea.y + workArea.height - height;
|
||||
break;
|
||||
}
|
||||
return {
|
||||
x: Math.round(x),
|
||||
y: Math.round(y),
|
||||
};
|
||||
};
|
||||
|
||||
const toast = (
|
||||
msg: string,
|
||||
options?: {
|
||||
duration?: number;
|
||||
status?: "success" | "error" | "info";
|
||||
},
|
||||
) => {
|
||||
return makeToast(msg, options);
|
||||
};
|
||||
|
||||
ipcMain.handle("app:toast", (event, msg: string, option?: any) => {
|
||||
return toast(msg, option);
|
||||
});
|
||||
|
||||
const loading = (
|
||||
msg: string,
|
||||
options?: {
|
||||
timeout?: number;
|
||||
percentAuto?: boolean;
|
||||
percentTotalSeconds?: number;
|
||||
},
|
||||
): {
|
||||
close: () => void;
|
||||
percent: (value: number) => void;
|
||||
} => {
|
||||
return makeLoading(msg, options);
|
||||
};
|
||||
|
||||
ipcMain.handle("app:loading", (event, msg: string, option?: any) => {
|
||||
return loading(msg, option);
|
||||
});
|
||||
|
||||
ipcMain.handle("app:setupList", async () => {
|
||||
return SetupMain.list();
|
||||
});
|
||||
|
||||
ipcMain.handle("app:setupOpen", async (event, name: string) => {
|
||||
return SetupMain.open(name);
|
||||
});
|
||||
|
||||
const setupIsOk = async () => {
|
||||
return SetupMain.isOk();
|
||||
};
|
||||
|
||||
ipcMain.handle("app:setupIsOk", async () => {
|
||||
return setupIsOk();
|
||||
});
|
||||
|
||||
const getBuildInfo = async () => {
|
||||
if (isDev) {
|
||||
return {
|
||||
buildId: "Development",
|
||||
};
|
||||
}
|
||||
const json = await Files.read(rendererDistPath("build.json"), {
|
||||
isDataPath: false,
|
||||
});
|
||||
return JSON.parse(json);
|
||||
};
|
||||
|
||||
ipcMain.handle("app:getBuildInfo", async () => {
|
||||
return getBuildInfo();
|
||||
});
|
||||
|
||||
const collect = async (options?: {}) => {
|
||||
return {
|
||||
userAgent: Apps.getUserAgent(),
|
||||
name: AppConfig.name,
|
||||
version: AppConfig.version,
|
||||
uuid: platformUUID(),
|
||||
platformVersion: platformVersion(),
|
||||
platformName: platformName(),
|
||||
platformArch: platformArch(),
|
||||
};
|
||||
};
|
||||
|
||||
ipcMain.handle("app:collect", async (event, options?: {}) => {
|
||||
return collect(options);
|
||||
});
|
||||
|
||||
const setAutoLaunch = async (enable: boolean, options?: {}) => {
|
||||
return app.setLoginItemSettings({
|
||||
openAtLogin: enable,
|
||||
});
|
||||
};
|
||||
|
||||
ipcMain.handle(
|
||||
"app:setAutoLaunch",
|
||||
async (event, enable: boolean, options?: {}) => {
|
||||
return setAutoLaunch(enable, options);
|
||||
},
|
||||
);
|
||||
|
||||
const getAutoLaunch = async (options?: {}) => {
|
||||
return app.getLoginItemSettings().openAtLogin;
|
||||
};
|
||||
|
||||
ipcMain.handle("app:getAutoLaunch", async (event, options?: {}) => {
|
||||
return getAutoLaunch(options);
|
||||
});
|
||||
|
||||
export default {
|
||||
quit,
|
||||
};
|
||||
|
||||
export const AppsMain = {
|
||||
shouldDarkMode,
|
||||
defaultDarkModeBackgroundColor,
|
||||
getWindowByName,
|
||||
getClipboardText,
|
||||
setClipboardText,
|
||||
getClipboardImage,
|
||||
setClipboardImage,
|
||||
getCurrentScreenDisplay,
|
||||
calcPositionInCurrentDisplay,
|
||||
toast,
|
||||
loading,
|
||||
setupIsOk,
|
||||
windowOpen,
|
||||
};
|
||||
193
vendor/aigcpanel/electron/mapi/app/render.ts
vendored
Normal file
193
vendor/aigcpanel/electron/mapi/app/render.ts
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
import { ipcRenderer } from "electron";
|
||||
import { resolve } from "node:path";
|
||||
import { isPackaged, platformArch, platformName } from "../../lib/env";
|
||||
import { AppEnv, waitAppEnvReady } from "../env";
|
||||
import appIndex from "./index";
|
||||
|
||||
const isDarkMode = async () => {
|
||||
return ipcRenderer.invoke("app:isDarkMode");
|
||||
};
|
||||
|
||||
const quit = () => {
|
||||
return ipcRenderer.invoke("app:quit");
|
||||
};
|
||||
|
||||
const restart = () => {
|
||||
return ipcRenderer.invoke("app:restart");
|
||||
};
|
||||
|
||||
const isPlatform = (name: "win" | "osx" | "linux") => {
|
||||
return platformName() === name;
|
||||
};
|
||||
|
||||
const windowMin = (name?: string) => {
|
||||
return ipcRenderer.invoke("window:min", name);
|
||||
};
|
||||
|
||||
const windowMax = (name?: string) => {
|
||||
return ipcRenderer.invoke("window:max", name);
|
||||
};
|
||||
|
||||
const windowSetSize = (
|
||||
name: string | null,
|
||||
width: number,
|
||||
height: number,
|
||||
option?: {
|
||||
includeMinimumSize: boolean;
|
||||
center: boolean;
|
||||
},
|
||||
) => {
|
||||
return ipcRenderer.invoke("window:setSize", name, width, height, option);
|
||||
};
|
||||
|
||||
const windowOpen = (name: string, option: any) => {
|
||||
return ipcRenderer.invoke("window:open", name, option);
|
||||
};
|
||||
|
||||
const windowHide = (name: string) => {
|
||||
return ipcRenderer.invoke("window:hide", name);
|
||||
};
|
||||
|
||||
const windowClose = (name: string) => {
|
||||
return ipcRenderer.invoke("window:close", name);
|
||||
};
|
||||
|
||||
const windowMove = (
|
||||
name: string | null,
|
||||
data: { mouseX: number; mouseY: number; width: number; height: number },
|
||||
) => {
|
||||
return ipcRenderer.invoke("window:move", name, data);
|
||||
};
|
||||
|
||||
const openExternal = (url: string) => {
|
||||
return ipcRenderer.invoke("app:openExternal", url);
|
||||
};
|
||||
|
||||
const openPath = (url: string) => {
|
||||
return ipcRenderer.invoke("app:openPath", url);
|
||||
};
|
||||
|
||||
const showItemInFolder = (url: string) => {
|
||||
return ipcRenderer.invoke("app:showItemInFolder", url);
|
||||
};
|
||||
|
||||
const getPreload = async () => {
|
||||
return ipcRenderer.invoke("app:getPreload");
|
||||
};
|
||||
|
||||
const resourcePathResolve = async (filePath: string) => {
|
||||
await waitAppEnvReady();
|
||||
const basePath = isPackaged ? process.resourcesPath : AppEnv.appRoot;
|
||||
return resolve(basePath, filePath);
|
||||
};
|
||||
|
||||
const extraPathResolve = async (filePath: string) => {
|
||||
await waitAppEnvReady();
|
||||
const basePath = isPackaged ? process.resourcesPath : "electron/resources";
|
||||
return resolve(basePath, "extra", filePath);
|
||||
};
|
||||
|
||||
const appEnv = async () => {
|
||||
await waitAppEnvReady();
|
||||
return AppEnv;
|
||||
};
|
||||
|
||||
const setRenderAppEnv = (env: any) => {
|
||||
AppEnv.isInit = true;
|
||||
AppEnv.appRoot = env.appRoot;
|
||||
AppEnv.appData = env.appData;
|
||||
AppEnv.userData = env.userData;
|
||||
AppEnv.dataRoot = env.dataRoot;
|
||||
};
|
||||
|
||||
const getClipboardText = () => {
|
||||
return ipcRenderer.invoke("app:getClipboardText");
|
||||
};
|
||||
|
||||
const setClipboardText = (text: string) => {
|
||||
return ipcRenderer.invoke("app:setClipboardText", text);
|
||||
};
|
||||
|
||||
const getClipboardImage = () => {
|
||||
return ipcRenderer.invoke("app:getClipboardImage");
|
||||
};
|
||||
|
||||
const setClipboardImage = (image: string) => {
|
||||
return ipcRenderer.invoke("app:setClipboardImage", image);
|
||||
};
|
||||
|
||||
const toast = (msg: string, option?: any) => {
|
||||
return ipcRenderer.invoke("app:toast", msg, option);
|
||||
};
|
||||
|
||||
const setupList = () => {
|
||||
return ipcRenderer.invoke("app:setupList");
|
||||
};
|
||||
|
||||
const setupOpen = (name: string) => {
|
||||
return ipcRenderer.invoke("app:setupOpen", name);
|
||||
};
|
||||
|
||||
const setupIsOk = async () => {
|
||||
return ipcRenderer.invoke("app:setupIsOk");
|
||||
};
|
||||
|
||||
const getBuildInfo = async () => {
|
||||
return ipcRenderer.invoke("app:getBuildInfo");
|
||||
};
|
||||
|
||||
const collect = async (options?: {}) => {
|
||||
return ipcRenderer.invoke("app:collect", options);
|
||||
};
|
||||
|
||||
const setAutoLaunch = async (enable: boolean, options?: {}) => {
|
||||
return ipcRenderer.invoke("app:setAutoLaunch", enable, options);
|
||||
};
|
||||
|
||||
const getAutoLaunch = async (options?: {}) => {
|
||||
return ipcRenderer.invoke("app:getAutoLaunch", options);
|
||||
};
|
||||
|
||||
export const AppsRender = {
|
||||
isDarkMode,
|
||||
resourcePathResolve,
|
||||
extraPathResolve,
|
||||
platformName,
|
||||
platformArch,
|
||||
isPlatform,
|
||||
quit,
|
||||
restart,
|
||||
windowMin,
|
||||
windowMax,
|
||||
windowSetSize,
|
||||
windowOpen,
|
||||
windowHide,
|
||||
windowClose,
|
||||
windowMove,
|
||||
openExternal,
|
||||
openPath,
|
||||
showItemInFolder,
|
||||
getPreload,
|
||||
appEnv,
|
||||
setRenderAppEnv,
|
||||
getClipboardText,
|
||||
setClipboardText,
|
||||
getClipboardImage,
|
||||
setClipboardImage,
|
||||
toast,
|
||||
setupList,
|
||||
setupOpen,
|
||||
setupIsOk,
|
||||
getBuildInfo,
|
||||
collect,
|
||||
setAutoLaunch,
|
||||
getAutoLaunch,
|
||||
shell: appIndex.shell,
|
||||
spawnShell: appIndex.spawnShell,
|
||||
spawnBinary: appIndex.spawnBinary,
|
||||
availablePort: appIndex.availablePort,
|
||||
fixExecutable: appIndex.fixExecutable,
|
||||
getUserAgent: appIndex.getUserAgent,
|
||||
};
|
||||
|
||||
export default AppsRender;
|
||||
49
vendor/aigcpanel/electron/mapi/app/setup.ts
vendored
Normal file
49
vendor/aigcpanel/electron/mapi/app/setup.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Permissions } from "../../lib/permission";
|
||||
|
||||
export const SetupMain = {
|
||||
async isOk() {
|
||||
return true;
|
||||
},
|
||||
async list() {
|
||||
return [
|
||||
{
|
||||
name: "accessibility",
|
||||
title: t("setup.accessibility.title"),
|
||||
status: (await Permissions.checkAccessibilityAccess())
|
||||
? "success"
|
||||
: "fail",
|
||||
desc: t("setup.accessibility.desc"),
|
||||
steps: [
|
||||
{
|
||||
title: t("setup.accessibility.step"),
|
||||
image: "/setup/accessibility.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "screen",
|
||||
title: t("setup.screen.title"),
|
||||
status: (await Permissions.checkScreenCaptureAccess())
|
||||
? "success"
|
||||
: "fail",
|
||||
desc: t("setup.screen.desc"),
|
||||
steps: [
|
||||
{
|
||||
title: t("setup.screen.step"),
|
||||
image: "/setup/screen.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
async open(name: string) {
|
||||
switch (name) {
|
||||
case "accessibility":
|
||||
Permissions.askAccessibilityAccess().then();
|
||||
break;
|
||||
case "screen":
|
||||
Permissions.askScreenCaptureAccess().then();
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
170
vendor/aigcpanel/electron/mapi/app/toast.ts
vendored
Normal file
170
vendor/aigcpanel/electron/mapi/app/toast.ts
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
import { BrowserWindow } from "electron";
|
||||
import { icons } from "./icons";
|
||||
import { AppsMain } from "./main";
|
||||
|
||||
let win = null;
|
||||
let winCloseTimer = null;
|
||||
let winShowTime = null;
|
||||
const toastMsgQueue: { msg: string; options: any }[] = [];
|
||||
|
||||
export const makeToast = async (
|
||||
msg: string,
|
||||
options?: {
|
||||
duration?: number;
|
||||
status?: "success" | "error" | "info";
|
||||
},
|
||||
) => {
|
||||
if (win) {
|
||||
if (winShowTime && Date.now() - winShowTime < 1000) {
|
||||
// make previous toast last at least 1 second
|
||||
if (toastMsgQueue.length > 0) {
|
||||
toastMsgQueue.forEach((item) => {
|
||||
item.options = Object.assign({}, item.options, {
|
||||
duration: 1000,
|
||||
});
|
||||
});
|
||||
}
|
||||
toastMsgQueue.push({ msg, options });
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, 1000 - (Date.now() - winShowTime)),
|
||||
);
|
||||
if (win) {
|
||||
win.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
win.close();
|
||||
}
|
||||
winShowTime = Date.now();
|
||||
|
||||
options = Object.assign(
|
||||
{
|
||||
status: "info",
|
||||
duration: 0,
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
if (options.duration === 0) {
|
||||
options.duration = Math.max(msg.length * 400, 3000);
|
||||
}
|
||||
// console.log('toast', msg, options)
|
||||
|
||||
const display = AppsMain.getCurrentScreenDisplay();
|
||||
// console.log('xxxx', primaryDisplay);
|
||||
const width = display.workArea.width;
|
||||
const height = 60;
|
||||
const icon = icons[options.status] || icons.success;
|
||||
|
||||
win = new BrowserWindow({
|
||||
height,
|
||||
width,
|
||||
parent: null,
|
||||
x: 0,
|
||||
y: 0,
|
||||
modal: false,
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
// opacity: 0.9,
|
||||
center: false,
|
||||
transparent: true,
|
||||
hasShadow: false,
|
||||
show: false,
|
||||
focusable: false,
|
||||
skipTaskbar: true,
|
||||
});
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html,body{
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: #FFFFFF;
|
||||
font-family: "PingFang SC", "Helvetica Neue", Helvetica, STHeiTi, "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
|
||||
}
|
||||
.message-view {
|
||||
height: 100%;
|
||||
text-align:center;
|
||||
box-sizing: border-box;
|
||||
background-color:transparent;
|
||||
padding: 10px;
|
||||
}
|
||||
.message-view div{
|
||||
margin: auto;
|
||||
font-size: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
line-height: 20px;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
border-radius: 15px;
|
||||
padding: 10px 10px;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.3);
|
||||
}
|
||||
.message-view div .icon{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display:inline-block;
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="message-view" onclick="window.close()">
|
||||
<div id="message">${icon}${msg}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const encodedHTML = encodeURIComponent(htmlContent);
|
||||
win.loadURL(`data:text/html;charset=UTF-8,${encodedHTML}`);
|
||||
win.on("ready-to-show", async () => {
|
||||
if (!win) return;
|
||||
const containerSize = await win.webContents.executeJavaScript(`(()=>{
|
||||
const message = document.getElementById('message');
|
||||
const width = message.scrollWidth;
|
||||
const height = message.scrollHeight;
|
||||
return {width:width,height:height};
|
||||
})()`);
|
||||
// console.log('containerSize', containerSize);
|
||||
const containerWidth = containerSize.width + 20;
|
||||
const containerHeight = containerSize.height + 20;
|
||||
win.setSize(containerWidth, containerHeight);
|
||||
const x =
|
||||
display.workArea.x +
|
||||
display.workArea.width / 2 -
|
||||
containerWidth / 2;
|
||||
const y = display.workArea.y + (display.workArea.height * 1) / 4;
|
||||
win.setPosition(Math.floor(x), Math.floor(y));
|
||||
win.showInactive();
|
||||
// win.webContents.openDevTools({
|
||||
// mode: 'detach'
|
||||
// })
|
||||
});
|
||||
win.on("closed", () => {
|
||||
win = null;
|
||||
if (winCloseTimer) {
|
||||
clearTimeout(winCloseTimer);
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (toastMsgQueue.length > 0) {
|
||||
const item = toastMsgQueue.shift();
|
||||
makeToast(item.msg, item.options);
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
winCloseTimer = setTimeout(() => {
|
||||
winCloseTimer = null;
|
||||
if (!win) return;
|
||||
win.close();
|
||||
}, options.duration);
|
||||
};
|
||||
Reference in New Issue
Block a user