@aixnn/aixautots 0.0.0-stage → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -2
- package/dist/chunk-5BMFMDQR.js +18 -0
- package/dist/chunk-64Q7BBIQ.js +1347 -0
- package/dist/chunk-BSHHYM72.js +1074 -0
- package/dist/chunk-CVV7FOMQ.js +175 -0
- package/dist/chunk-EVHTAXQG.js +273 -0
- package/dist/chunk-FW23FLAF.js +56 -0
- package/dist/chunk-IJVNII5N.js +668 -0
- package/dist/chunk-NWFYTFMI.js +65 -0
- package/dist/chunk-O34SNDQB.js +2042 -0
- package/dist/chunk-OEZFYKL6.js +1 -0
- package/dist/chunk-OXIM6EYO.js +410 -0
- package/dist/chunk-SVK2AY3J.js +412 -0
- package/dist/chunk-TATL3HTE.js +1511 -0
- package/dist/chunk-UINEPEIE.js +217 -0
- package/dist/chunk-V4MXFPDX.js +341 -0
- package/dist/chunk-XNKC6HU3.js +866 -0
- package/dist/chunk-YOT7HZBU.js +5744 -0
- package/dist/core/index.js +5 -0
- package/dist/device-session-W7I3WQXF.js +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/nav/index.js +1 -0
- package/dist/react/index.js +7 -0
- package/dist/ui/billing.js +425 -0
- package/dist/ui/device-create.js +9 -0
- package/dist/ui/device-mirror.js +10 -0
- package/dist/ui/devices.js +15 -0
- package/dist/ui/editor.js +344 -0
- package/dist/ui/index.js +665 -0
- package/dist/ui/inspector.js +1250 -0
- package/dist/ui/market.js +60 -0
- package/dist/ui/mirror.js +3 -0
- package/dist/ui/primitives/index.js +1 -0
- package/dist/ui/script-studio.js +10 -0
- package/dist/ui/scripts.js +210 -0
- package/dist/ui/tasks.js +1039 -0
- package/package.json +75 -4
- package/styles.css +97 -0
- package/tailwind-preset.cjs +84 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { MirrorView, ControlBar } from './chunk-CVV7FOMQ.js';
|
|
2
|
+
import { useMirror, useDevices } from './chunk-O34SNDQB.js';
|
|
3
|
+
import { useClient } from './chunk-UINEPEIE.js';
|
|
4
|
+
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
5
|
+
import { RotateCw, Minimize2, Maximize2, X } from 'lucide-react';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var PHASES = {
|
|
9
|
+
android: [
|
|
10
|
+
[25, "\u6B63\u5728\u8FDE\u63A5\u8BBE\u5907\u2026"],
|
|
11
|
+
[55, "\u5EFA\u7ACB\u52A0\u5BC6\u901A\u9053\u2026"],
|
|
12
|
+
[80, "\u62C9\u53D6\u5B9E\u65F6\u753B\u9762\u2026"],
|
|
13
|
+
[95, "\u5373\u5C06\u5448\u73B0\u2026"]
|
|
14
|
+
],
|
|
15
|
+
ios: [
|
|
16
|
+
[25, "\u6B63\u5728\u8FDE\u63A5\u8BBE\u5907\u2026"],
|
|
17
|
+
[55, "\u5EFA\u7ACB\u52A0\u5BC6\u901A\u9053\u2026"],
|
|
18
|
+
[80, "\u62C9\u53D6\u5B9E\u65F6\u753B\u9762\u2026"],
|
|
19
|
+
[95, "\u5373\u5C06\u5448\u73B0\u2026"]
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
function phaseLabel(phases, p) {
|
|
23
|
+
for (const [ceil, label] of phases) if (p <= ceil) return label;
|
|
24
|
+
return "\u5373\u5C06\u5448\u73B0\u2026";
|
|
25
|
+
}
|
|
26
|
+
function DeviceBootSplash({ error, expectedMs = 3e3, platform = "android", className }) {
|
|
27
|
+
const [pct, setPct] = useState(4);
|
|
28
|
+
const startRef = useRef(Date.now());
|
|
29
|
+
const phases = PHASES[platform];
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (error) return;
|
|
32
|
+
startRef.current = Date.now();
|
|
33
|
+
setPct(4);
|
|
34
|
+
const id = setInterval(() => {
|
|
35
|
+
const elapsed = Date.now() - startRef.current;
|
|
36
|
+
const target = 95 * (1 - Math.exp(-elapsed / (expectedMs * 0.55)));
|
|
37
|
+
setPct((prev) => Math.max(prev, Math.min(95, Math.round(target))));
|
|
38
|
+
}, 250);
|
|
39
|
+
return () => clearInterval(id);
|
|
40
|
+
}, [error, expectedMs]);
|
|
41
|
+
if (error) {
|
|
42
|
+
return /* @__PURE__ */ jsxs(
|
|
43
|
+
"div",
|
|
44
|
+
{
|
|
45
|
+
className: `flex h-full w-full flex-col items-center justify-center gap-3 bg-black/80 px-6 text-center ${className ?? ""}`,
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx("div", { className: "text-2xl", children: "\u26A0\uFE0F" }),
|
|
48
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm text-white/80", children: [
|
|
49
|
+
"\u8FDE\u63A5\u5931\u8D25\uFF1A",
|
|
50
|
+
error
|
|
51
|
+
] }),
|
|
52
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-white/40", children: "\u8BBE\u5907\u9700\u5728\u7EBF\uFF1B\u82E5\u521A\u521B\u5EFA\uFF0C\u8BF7\u7B49\u5F85\u542F\u52A8\u5B8C\u6210\u540E\u91CD\u8BD5" })
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
className: `flex h-full w-full flex-col items-center justify-center gap-5 bg-gradient-to-b from-zinc-900 to-black px-8 ${className ?? ""}`,
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
"span",
|
|
65
|
+
{
|
|
66
|
+
className: `absolute h-20 w-20 animate-ping rounded-full ${platform === "ios" ? "bg-sky-300/20" : "bg-emerald-400/20"}`
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
"span",
|
|
71
|
+
{
|
|
72
|
+
className: `absolute h-16 w-16 animate-pulse rounded-full ${platform === "ios" ? "bg-sky-300/10" : "bg-emerald-400/10"}`
|
|
73
|
+
}
|
|
74
|
+
),
|
|
75
|
+
platform === "ios" ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-12 w-12 text-sky-200", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M16.37 12.78c-.02-2.05 1.67-3.03 1.75-3.08-.95-1.39-2.43-1.58-2.96-1.6-1.26-.13-2.46.74-3.1.74-.64 0-1.62-.72-2.66-.7-1.37.02-2.63.8-3.33 2.02-1.42 2.47-.36 6.12 1.02 8.13.67.98 1.48 2.08 2.53 2.04 1.02-.04 1.4-.66 2.63-.66 1.22 0 1.57.66 2.65.64 1.09-.02 1.79-1 2.46-1.98.77-1.13 1.09-2.23 1.11-2.29-.02-.01-2.13-.82-2.15-3.25ZM14.4 6.45c.56-.68.94-1.62.84-2.56-.81.03-1.79.54-2.37 1.21-.52.6-.97 1.56-.85 2.48.9.07 1.82-.46 2.38-1.13Z" }) }) : /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-12 w-12 text-emerald-400", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M6 9a6 6 0 0 1 12 0v6a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V9Zm2.5-3.2 -1-1.6a.4.4 0 0 1 .7-.4l1.05 1.7a6.7 6.7 0 0 1 3.5 0l1.05-1.7a.4.4 0 1 1 .7.4l-1 1.6A6 6 0 0 0 8.5 5.8ZM9.5 9.2a.9.9 0 1 0 0 1.8.9.9 0 0 0 0-1.8Zm5 0a.9.9 0 1 0 0 1.8.9.9 0 0 0 0-1.8ZM5 11a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0v-4a1 1 0 0 1 1-1Zm14 0a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0v-4a1 1 0 0 1 1-1ZM9 17h6a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1 1 1 0 1 1-2 0h-2a1 1 0 1 1-2 0 1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1Z" }) })
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full max-w-[220px] space-y-2", children: [
|
|
78
|
+
/* @__PURE__ */ jsx("div", { className: "h-1.5 w-full overflow-hidden rounded-full bg-white/10", children: /* @__PURE__ */ jsx(
|
|
79
|
+
"div",
|
|
80
|
+
{
|
|
81
|
+
className: `h-full rounded-full transition-[width] duration-300 ease-out ${platform === "ios" ? "bg-sky-300" : "bg-emerald-400"}`,
|
|
82
|
+
style: { width: `${pct}%` }
|
|
83
|
+
}
|
|
84
|
+
) }),
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/70", children: phaseLabel(phases, pct) }),
|
|
87
|
+
/* @__PURE__ */ jsxs("span", { className: "tabular-nums text-white/40", children: [
|
|
88
|
+
pct,
|
|
89
|
+
"%"
|
|
90
|
+
] })
|
|
91
|
+
] })
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] text-white/30", children: "\u6B63\u5728\u8FDE\u63A5\u5B9E\u65F6\u753B\u9762\uFF0C\u5C31\u7EEA\u540E\u81EA\u52A8\u663E\u793A" })
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/core/quality-auto.ts
|
|
100
|
+
var RTT_HIGH = 0.15;
|
|
101
|
+
var RTT_LOW = 0.04;
|
|
102
|
+
var HYSTERESIS = 0.03;
|
|
103
|
+
function pickAutoProfile(rtt, current) {
|
|
104
|
+
if (current === "low_latency") {
|
|
105
|
+
if (rtt >= RTT_HIGH - HYSTERESIS) return "low_latency";
|
|
106
|
+
return rtt < RTT_LOW ? "high_quality" : "balanced";
|
|
107
|
+
}
|
|
108
|
+
if (current === "high_quality") {
|
|
109
|
+
if (rtt <= RTT_LOW + HYSTERESIS) return "high_quality";
|
|
110
|
+
return rtt > RTT_HIGH ? "low_latency" : "balanced";
|
|
111
|
+
}
|
|
112
|
+
if (rtt > RTT_HIGH) return "low_latency";
|
|
113
|
+
if (rtt < RTT_LOW) return "high_quality";
|
|
114
|
+
return "balanced";
|
|
115
|
+
}
|
|
116
|
+
var PROFILE_LABELS = {
|
|
117
|
+
balanced: "\u5E73\u8861",
|
|
118
|
+
low_latency: "\u4F4E\u5EF6\u8FDF",
|
|
119
|
+
high_quality: "\u9AD8\u753B\u8D28"
|
|
120
|
+
};
|
|
121
|
+
var DEFAULT_SIZE = { width: 1080, height: 2340 };
|
|
122
|
+
var AUTO_QUALITY_FIRST_CHECK_MS = 2e3;
|
|
123
|
+
var AUTO_QUALITY_INTERVAL_MS = 8e3;
|
|
124
|
+
var AUTO_QUALITY_MIN_SWITCH_INTERVAL_MS = 15e3;
|
|
125
|
+
function MirrorSurface({ deviceId, platform = "android", onSize, videoAspect, shortcutBar, className }) {
|
|
126
|
+
const { stream, error, sendInput, setQuality, session } = useMirror(deviceId);
|
|
127
|
+
const [size, setSize] = useState(DEFAULT_SIZE);
|
|
128
|
+
const [hasFrame, setHasFrame] = useState(false);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
setHasFrame(false);
|
|
131
|
+
}, [deviceId, stream]);
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
setSize(DEFAULT_SIZE);
|
|
134
|
+
onSize?.(DEFAULT_SIZE);
|
|
135
|
+
}, [deviceId, onSize]);
|
|
136
|
+
const [profile, setProfile] = useState("balanced");
|
|
137
|
+
const manualRef = useRef(false);
|
|
138
|
+
const changeProfile = useCallback(
|
|
139
|
+
(p, manual) => {
|
|
140
|
+
if (manual) manualRef.current = true;
|
|
141
|
+
setProfile(p);
|
|
142
|
+
setQuality(p);
|
|
143
|
+
},
|
|
144
|
+
[setQuality]
|
|
145
|
+
);
|
|
146
|
+
const [landscape, setLandscape] = useState(false);
|
|
147
|
+
const toggleOrientation = useCallback(() => {
|
|
148
|
+
setLandscape((prev) => {
|
|
149
|
+
const next = !prev;
|
|
150
|
+
sendInput({ t: "rotate", orientation: next ? "landscape" : "portrait" });
|
|
151
|
+
return next;
|
|
152
|
+
});
|
|
153
|
+
}, [sendInput]);
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
manualRef.current = false;
|
|
156
|
+
setProfile("balanced");
|
|
157
|
+
setLandscape(false);
|
|
158
|
+
}, [deviceId]);
|
|
159
|
+
const profileRef = useRef(profile);
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
profileRef.current = profile;
|
|
162
|
+
}, [profile]);
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
if (!stream || !session) return;
|
|
165
|
+
let cancelled = false;
|
|
166
|
+
let lastSwitchAt = 0;
|
|
167
|
+
const check = async () => {
|
|
168
|
+
if (cancelled || manualRef.current) return;
|
|
169
|
+
const rtt = await session.currentRtt();
|
|
170
|
+
if (cancelled || rtt === null || manualRef.current) return;
|
|
171
|
+
const next = pickAutoProfile(rtt, profileRef.current);
|
|
172
|
+
if (next === profileRef.current) return;
|
|
173
|
+
const now = Date.now();
|
|
174
|
+
if (now - lastSwitchAt < AUTO_QUALITY_MIN_SWITCH_INTERVAL_MS) return;
|
|
175
|
+
lastSwitchAt = now;
|
|
176
|
+
changeProfile(next, false);
|
|
177
|
+
};
|
|
178
|
+
const first = setTimeout(check, AUTO_QUALITY_FIRST_CHECK_MS);
|
|
179
|
+
const interval = setInterval(check, AUTO_QUALITY_INTERVAL_MS);
|
|
180
|
+
return () => {
|
|
181
|
+
cancelled = true;
|
|
182
|
+
clearTimeout(first);
|
|
183
|
+
clearInterval(interval);
|
|
184
|
+
};
|
|
185
|
+
}, [stream, session, changeProfile]);
|
|
186
|
+
const reportSize = useCallback(
|
|
187
|
+
(real) => {
|
|
188
|
+
if (real.width > 0 && real.height > 0) {
|
|
189
|
+
setSize(real);
|
|
190
|
+
onSize?.(real);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
[onSize]
|
|
194
|
+
);
|
|
195
|
+
const handleFirstFrame = useCallback(
|
|
196
|
+
(real) => {
|
|
197
|
+
setHasFrame(true);
|
|
198
|
+
reportSize(real);
|
|
199
|
+
},
|
|
200
|
+
[reportSize]
|
|
201
|
+
);
|
|
202
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex min-h-0 flex-col items-center gap-2 ${className ?? ""}`, children: [
|
|
203
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 w-full flex-1 items-stretch justify-center gap-2", children: [
|
|
204
|
+
shortcutBar,
|
|
205
|
+
/* @__PURE__ */ jsxs(
|
|
206
|
+
"div",
|
|
207
|
+
{
|
|
208
|
+
className: `relative min-h-0 overflow-hidden rounded-lg ${videoAspect ? "h-full" : "h-full flex-1"}`,
|
|
209
|
+
style: videoAspect ? { aspectRatio: String(videoAspect) } : void 0,
|
|
210
|
+
children: [
|
|
211
|
+
stream && /* @__PURE__ */ jsx(
|
|
212
|
+
MirrorView,
|
|
213
|
+
{
|
|
214
|
+
stream,
|
|
215
|
+
deviceSize: size,
|
|
216
|
+
onInput: sendInput,
|
|
217
|
+
onFirstFrame: handleFirstFrame,
|
|
218
|
+
onResize: reportSize,
|
|
219
|
+
continuousTouch: platform === "android",
|
|
220
|
+
className: "h-full w-full"
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
(!stream || !hasFrame) && /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx(
|
|
224
|
+
DeviceBootSplash,
|
|
225
|
+
{
|
|
226
|
+
error: error ? error.message : null,
|
|
227
|
+
platform,
|
|
228
|
+
className: "rounded-lg"
|
|
229
|
+
}
|
|
230
|
+
) })
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
)
|
|
234
|
+
] }),
|
|
235
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
236
|
+
/* @__PURE__ */ jsx(
|
|
237
|
+
ControlBar,
|
|
238
|
+
{
|
|
239
|
+
platform,
|
|
240
|
+
onBack: () => sendInput({ t: "back" }),
|
|
241
|
+
onHome: () => sendInput({ t: "home" }),
|
|
242
|
+
onMenu: () => sendInput({ t: "key", code: "app_switch" })
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
/* @__PURE__ */ jsx(
|
|
246
|
+
"select",
|
|
247
|
+
{
|
|
248
|
+
"aria-label": "\u753B\u8D28\u6863\u4F4D",
|
|
249
|
+
value: profile,
|
|
250
|
+
onChange: (e) => changeProfile(e.target.value, true),
|
|
251
|
+
className: "rounded border border-border bg-secondary px-2 py-1 text-xs text-foreground outline-none hover:bg-card",
|
|
252
|
+
children: Object.keys(PROFILE_LABELS).map((p) => /* @__PURE__ */ jsx("option", { value: p, children: PROFILE_LABELS[p] }, p))
|
|
253
|
+
}
|
|
254
|
+
),
|
|
255
|
+
platform === "android" && /* @__PURE__ */ jsxs(
|
|
256
|
+
"button",
|
|
257
|
+
{
|
|
258
|
+
type: "button",
|
|
259
|
+
onClick: toggleOrientation,
|
|
260
|
+
"aria-label": landscape ? "\u5207\u56DE\u7AD6\u5C4F" : "\u5207\u6362\u6A2A\u5C4F",
|
|
261
|
+
title: landscape ? "\u5207\u56DE\u7AD6\u5C4F" : "\u5207\u6362\u6A2A\u5C4F",
|
|
262
|
+
"aria-pressed": landscape,
|
|
263
|
+
className: `flex items-center gap-1 rounded border border-border px-2 py-1 text-xs outline-none hover:bg-card ${landscape ? "bg-primary/15 text-primary" : "bg-secondary text-foreground"}`,
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ jsx(RotateCw, { className: "h-3.5 w-3.5" }),
|
|
266
|
+
landscape ? "\u7AD6\u5C4F" : "\u6A2A\u5C4F"
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
] })
|
|
271
|
+
] });
|
|
272
|
+
}
|
|
273
|
+
function DeviceMirror({ deviceId, deviceName, platform = "android", shortcutBar, onClose }) {
|
|
274
|
+
const open = deviceId !== null;
|
|
275
|
+
const client = useClient();
|
|
276
|
+
const { data: devices } = useDevices();
|
|
277
|
+
const [size, setSize] = useState({ width: 1080, height: 2340 });
|
|
278
|
+
const overlayRef = useRef(null);
|
|
279
|
+
const [fullscreen, setFullscreen] = useState(false);
|
|
280
|
+
const sleepTimeoutMin = useMemo(() => {
|
|
281
|
+
if (!deviceId) return 30;
|
|
282
|
+
const d = devices?.find((dv) => dv.external_id === deviceId);
|
|
283
|
+
const v = d?.meta?.sleep_timeout_min;
|
|
284
|
+
return typeof v === "number" ? v : 30;
|
|
285
|
+
}, [devices, deviceId]);
|
|
286
|
+
const lastActivityRef = useRef(Date.now());
|
|
287
|
+
const resetActivity = useCallback(() => {
|
|
288
|
+
lastActivityRef.current = Date.now();
|
|
289
|
+
}, []);
|
|
290
|
+
useEffect(() => {
|
|
291
|
+
if (!open || !deviceId || sleepTimeoutMin === 0) return;
|
|
292
|
+
const ms = sleepTimeoutMin * 60 * 1e3;
|
|
293
|
+
const id = setInterval(() => {
|
|
294
|
+
if (Date.now() - lastActivityRef.current >= ms) {
|
|
295
|
+
void client.devices.sleep(deviceId).then(() => onClose()).catch(() => {
|
|
296
|
+
});
|
|
297
|
+
clearInterval(id);
|
|
298
|
+
}
|
|
299
|
+
}, 1e4);
|
|
300
|
+
return () => clearInterval(id);
|
|
301
|
+
}, [open, deviceId, sleepTimeoutMin, onClose, client]);
|
|
302
|
+
const enterFullscreen = useCallback(async () => {
|
|
303
|
+
const el = overlayRef.current;
|
|
304
|
+
if (!el) return;
|
|
305
|
+
try {
|
|
306
|
+
if (el.requestFullscreen) await el.requestFullscreen();
|
|
307
|
+
else if (el.webkitRequestFullscreen) await el.webkitRequestFullscreen();
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
}, []);
|
|
311
|
+
const exitFullscreen = useCallback(async () => {
|
|
312
|
+
const doc = document;
|
|
313
|
+
try {
|
|
314
|
+
if (doc.fullscreenElement && doc.exitFullscreen) await doc.exitFullscreen();
|
|
315
|
+
else if (doc.webkitFullscreenElement && doc.webkitExitFullscreen) await doc.webkitExitFullscreen();
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
}, []);
|
|
319
|
+
const toggleFullscreen = useCallback(() => {
|
|
320
|
+
if (fullscreen) void exitFullscreen();
|
|
321
|
+
else void enterFullscreen();
|
|
322
|
+
}, [fullscreen, enterFullscreen, exitFullscreen]);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
const onFsChange = () => {
|
|
325
|
+
const doc = document;
|
|
326
|
+
const fsEl = doc.fullscreenElement || doc.webkitFullscreenElement || null;
|
|
327
|
+
setFullscreen(fsEl === overlayRef.current);
|
|
328
|
+
};
|
|
329
|
+
document.addEventListener("fullscreenchange", onFsChange);
|
|
330
|
+
document.addEventListener("webkitfullscreenchange", onFsChange);
|
|
331
|
+
return () => {
|
|
332
|
+
document.removeEventListener("fullscreenchange", onFsChange);
|
|
333
|
+
document.removeEventListener("webkitfullscreenchange", onFsChange);
|
|
334
|
+
};
|
|
335
|
+
}, []);
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
if (!open) return;
|
|
338
|
+
const onKey = (e) => {
|
|
339
|
+
resetActivity();
|
|
340
|
+
if (e.key === "Escape" && !fullscreen) onClose();
|
|
341
|
+
};
|
|
342
|
+
window.addEventListener("keydown", onKey);
|
|
343
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
344
|
+
}, [open, onClose, resetActivity, fullscreen]);
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
if (!open) void exitFullscreen();
|
|
347
|
+
}, [open, exitFullscreen]);
|
|
348
|
+
const stop = useCallback((e) => e.stopPropagation(), []);
|
|
349
|
+
if (!open) return null;
|
|
350
|
+
const aspect = size.width > 0 && size.height > 0 ? size.width / size.height : 9 / 16;
|
|
351
|
+
return /* @__PURE__ */ jsx(
|
|
352
|
+
"div",
|
|
353
|
+
{
|
|
354
|
+
ref: overlayRef,
|
|
355
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm",
|
|
356
|
+
onClick: onClose,
|
|
357
|
+
onMouseMove: resetActivity,
|
|
358
|
+
onPointerDown: resetActivity,
|
|
359
|
+
children: /* @__PURE__ */ jsxs(
|
|
360
|
+
"div",
|
|
361
|
+
{
|
|
362
|
+
className: `flex flex-col items-center ${fullscreen ? "h-full w-full gap-1 py-2" : "gap-3"}`,
|
|
363
|
+
onClick: stop,
|
|
364
|
+
children: [
|
|
365
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-3 px-2 text-white/90", children: [
|
|
366
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium truncate max-w-[50vw]", children: [
|
|
367
|
+
deviceName || deviceId,
|
|
368
|
+
" \xB7 \u5B9E\u65F6\u955C\u50CF"
|
|
369
|
+
] }),
|
|
370
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
"button",
|
|
373
|
+
{
|
|
374
|
+
type: "button",
|
|
375
|
+
"aria-label": fullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
|
|
376
|
+
title: fullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
|
|
377
|
+
onClick: toggleFullscreen,
|
|
378
|
+
className: "rounded p-1 hover:bg-white/10",
|
|
379
|
+
children: fullscreen ? /* @__PURE__ */ jsx(Minimize2, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Maximize2, { className: "h-5 w-5" })
|
|
380
|
+
}
|
|
381
|
+
),
|
|
382
|
+
/* @__PURE__ */ jsx(
|
|
383
|
+
"button",
|
|
384
|
+
{
|
|
385
|
+
type: "button",
|
|
386
|
+
"aria-label": "\u5173\u95ED",
|
|
387
|
+
onClick: onClose,
|
|
388
|
+
className: "rounded p-1 hover:bg-white/10",
|
|
389
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
] })
|
|
393
|
+
] }),
|
|
394
|
+
/* @__PURE__ */ jsx("div", { className: `min-h-0 ${fullscreen ? "flex-1" : ""}`, style: fullscreen ? void 0 : { height: "80vh" }, children: /* @__PURE__ */ jsx(
|
|
395
|
+
MirrorSurface,
|
|
396
|
+
{
|
|
397
|
+
deviceId,
|
|
398
|
+
platform,
|
|
399
|
+
onSize: setSize,
|
|
400
|
+
videoAspect: aspect,
|
|
401
|
+
shortcutBar,
|
|
402
|
+
className: "h-full"
|
|
403
|
+
}
|
|
404
|
+
) })
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export { DeviceBootSplash, DeviceMirror, MirrorSurface };
|