@windypro-rourou/dsh-logcat 0.6.0-preview.5 → 0.6.0
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/lib/client.js +35 -9
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -139,6 +139,10 @@ window.__ModuleLoader__.load({
|
|
|
139
139
|
.lc-screen-img { flex: 1; min-height: 0; overflow: auto; display: flex; align-items: center; justify-content: center; cursor: crosshair; background: light-dark(rgba(0,0,0,.03), rgba(255,255,255,.03)); position: relative; }
|
|
140
140
|
.lc-screen-img img, .lc-screen-img canvas { max-width: 100%; max-height: 100%; object-fit: contain; user-select: none; }
|
|
141
141
|
.lc-screen-hint { color: light-dark(#6b7078, #9aa0a8); }
|
|
142
|
+
.lc-pausedbar { display: flex; align-items: center; gap: 8px; padding: 5px 12px; background: light-dark(rgba(251,192,45,.16), rgba(251,192,45,.18)); border-bottom: 1px solid rgba(251,192,45,.45); flex: none; font-size: 12px; color: #fbc02d; }
|
|
143
|
+
.lc-pausedbar .lc-btn { padding: 2px 10px; }
|
|
144
|
+
.lc-fab { position: absolute; right: 14px; bottom: 14px; z-index: 4; border: 1px solid rgba(66,133,244,.45); background: light-dark(rgba(66,133,244,.14), rgba(66,133,244,.24)); color: #4285f4; font: inherit; font-size: 12px; font-weight: 700; padding: 8px 14px; border-radius: 999px; cursor: pointer; box-shadow: 0 4px 14px rgba(0,0,0,.22); }
|
|
145
|
+
.lc-fab:hover { background: light-dark(rgba(66,133,244,.22), rgba(66,133,244,.34)); }
|
|
142
146
|
`;
|
|
143
147
|
//#endregion
|
|
144
148
|
|
|
@@ -183,6 +187,7 @@ window.__ModuleLoader__.load({
|
|
|
183
187
|
const [entries, setEntries] = useState([]);
|
|
184
188
|
const [connected, setConnected] = useState(false);
|
|
185
189
|
const [paused, setPaused] = useState(false);
|
|
190
|
+
const [pendingCount, setPendingCount] = useState(0);
|
|
186
191
|
const [currentPackage, setCurrentPackage] = useState("");
|
|
187
192
|
const [pkgInput, setPkgInput] = useState("");
|
|
188
193
|
const [installingAdb, setInstallingAdb] = useState(false);
|
|
@@ -299,10 +304,19 @@ window.__ModuleLoader__.load({
|
|
|
299
304
|
|
|
300
305
|
const appendEntries = (incoming) => {
|
|
301
306
|
const next = entriesRef.current.concat(incoming);
|
|
302
|
-
|
|
307
|
+
let removed = 0;
|
|
308
|
+
if (next.length > 5000) { removed = next.length - 5000; next.splice(0, removed); }
|
|
303
309
|
entriesRef.current = next;
|
|
304
310
|
setEntries(next);
|
|
305
|
-
if (autoScrollRef.current)
|
|
311
|
+
if (autoScrollRef.current) {
|
|
312
|
+
requestAnimationFrame(() => scrollToBottom());
|
|
313
|
+
} else if (removed > 0) {
|
|
314
|
+
// Anchor the viewport: trimming old rows shifts array indexes, so
|
|
315
|
+
// compensate the scroll position to keep what the user is reading
|
|
316
|
+
// visually in place (no jumping while auto-scroll is off).
|
|
317
|
+
const body = bodyRef.current;
|
|
318
|
+
if (body !== null) body.scrollTop = Math.max(0, body.scrollTop - removed * 20);
|
|
319
|
+
}
|
|
306
320
|
};
|
|
307
321
|
|
|
308
322
|
const applyFrame = (frame) => {
|
|
@@ -334,6 +348,7 @@ window.__ModuleLoader__.load({
|
|
|
334
348
|
if (pausedRef.current) {
|
|
335
349
|
pendingRef.current.push(frame);
|
|
336
350
|
if (pendingRef.current.length > 800) pendingRef.current.splice(0, pendingRef.current.length - 800);
|
|
351
|
+
setPendingCount(pendingRef.current.length);
|
|
337
352
|
return;
|
|
338
353
|
}
|
|
339
354
|
if (frame.serial !== serialRef.current) return;
|
|
@@ -495,10 +510,13 @@ window.__ModuleLoader__.load({
|
|
|
495
510
|
const togglePause = () => {
|
|
496
511
|
const next = !paused;
|
|
497
512
|
setPaused(next);
|
|
498
|
-
if (!next
|
|
499
|
-
|
|
500
|
-
pendingRef.current
|
|
501
|
-
|
|
513
|
+
if (!next) {
|
|
514
|
+
setPendingCount(0);
|
|
515
|
+
if (pendingRef.current.length > 0) {
|
|
516
|
+
const replay = pendingRef.current.filter((f) => f.serial === serialRef.current);
|
|
517
|
+
pendingRef.current = [];
|
|
518
|
+
if (replay.length > 0) appendEntries(replay.map((f) => f.entry));
|
|
519
|
+
}
|
|
502
520
|
}
|
|
503
521
|
};
|
|
504
522
|
|
|
@@ -953,7 +971,7 @@ window.__ModuleLoader__.load({
|
|
|
953
971
|
}),
|
|
954
972
|
h("button", { type: "button", className: "lc-btn", onClick: () => fileInputRef.current?.click(), title: "选择本地 APK 安装到当前设备", disabled: installingApk ? true : undefined }, installingApk ? "安装中…" : "装APK"),
|
|
955
973
|
h("button", { type: "button", className: "lc-btn", "data-on": paused ? "" : undefined, onClick: togglePause },
|
|
956
|
-
paused ? "继续" : "暂停"),
|
|
974
|
+
paused ? "继续(" + pendingCount + ")" : "暂停"),
|
|
957
975
|
h("button", { type: "button", className: "lc-btn", onClick: clearLog }, "清空"),
|
|
958
976
|
h("button", { type: "button", className: "lc-btn", onClick: copyLog }, "复制"),
|
|
959
977
|
h("button", { type: "button", className: "lc-btn", onClick: exportLog }, "导出"),
|
|
@@ -986,10 +1004,15 @@ window.__ModuleLoader__.load({
|
|
|
986
1004
|
h("button", { type: "button", className: "lc-btn", onClick: () => setHistoryNote("") }, "关闭"),
|
|
987
1005
|
)
|
|
988
1006
|
: null,
|
|
1007
|
+
paused && tab === "log" && !eventsOn
|
|
1008
|
+
? h("div", { className: "lc-pausedbar" },
|
|
1009
|
+
h("span", { style: { flex: 1 } }, "⏸ 已暂停 — 新日志缓冲中(" + pendingCount + " 条),列表已冻结"),
|
|
1010
|
+
h("button", { type: "button", className: "lc-btn", onClick: togglePause, title: "恢复实时,回放缓冲日志" }, "继续"),
|
|
1011
|
+
)
|
|
1012
|
+
: null,
|
|
989
1013
|
h("div", { className: "lc-body", ref: bodyRef },
|
|
990
1014
|
tab === "re"
|
|
991
|
-
? h("div", { className: "lc-re" },
|
|
992
|
-
h("div", { className: "lc-re-top" },
|
|
1015
|
+
? h("div", { className: "lc-re" }, h("div", { className: "lc-re-top" },
|
|
993
1016
|
h("input", { placeholder: "进程过滤…", value: reFilter, onChange: (e) => setReFilter(e.target.value), onKeyDown: (e) => { if (e.key === "Enter") loadProcesses(); }, style: { width: 120 } }),
|
|
994
1017
|
h("button", { type: "button", className: "lc-btn", onClick: loadProcesses }, "进程"),
|
|
995
1018
|
h("input", { placeholder: "搜索: hello 或 hex:48656c6c6f", value: rePattern, onChange: (e) => setRePattern(e.target.value), onKeyDown: (e) => { if (e.key === "Enter") reSearch(); }, style: { flex: 1, minWidth: 140 } }),
|
|
@@ -1041,6 +1064,9 @@ window.__ModuleLoader__.load({
|
|
|
1041
1064
|
: (filtered.length === 0
|
|
1042
1065
|
? h("div", { className: "lc-empty" }, paused ? "已暂停(" + entries.length + " 条已缓冲)" : "暂无日志")
|
|
1043
1066
|
: h(VirtualLog, { entries: filtered, scrollTop, onScrollTop: setScrollTop, bodyRef })),
|
|
1067
|
+
tab === "log" && !eventsOn && live && !paused
|
|
1068
|
+
? h("button", { type: "button", className: "lc-fab", onClick: togglePause, title: "暂停:冻结当前视图(新日志进入缓冲)" }, "⏸ 暂停")
|
|
1069
|
+
: null,
|
|
1044
1070
|
),
|
|
1045
1071
|
crashModal
|
|
1046
1072
|
? h("div", { className: "lc-overlay", onClick: () => setCrashModal(false) },
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windypro-rourou/dsh-logcat",
|
|
3
3
|
"description": "Android Logcat viewer for the dsh web GUI: auto-connects to any adb device in debug mode, live logcat stream with level/keyword filters, pause/clear/export, plus agent tools (logcat_recent). Hot-pluggable — mounted via ~/.dsh/cordis.patch.yml + a profile node_modules copy, no dsh source changes.",
|
|
4
|
-
"version": "0.6.0
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|
|
7
7
|
"engines": {
|