feat(ui): M6.38批 — P1 MD3细化(SDK对话框28)+批②底部上滑回桌面+批6 ncm顶栏回播放页+批④面板后台列表+launcher UI微调(歌词页黑半透明底/播放页布局下移)+封面空artwork保留修复
- P1: meow_ui_dialog.c 对话框底框 radius_card→MEOW_SHAPE_EXTRA_LARGE(28) 三处(:103填充/:104描边/:361 BottomSheet); meow_ui_widgets.h 新增 MEOW_SHAPE_EXTRA_LARGE 28 宏; TextField/FAB/Slider/Progress 按设计文档保留 - 批②: np_gesture.h 新增 NP_GEST_HOME+np_home_gesture(底部热区上滑,与左缘返回对称互斥); now_playing.c 新增 np_draw_home_bar(屏底左缘pill指示条)+手势衔接; test_now_playing_widgets G5b - 批6: ncm home.c 顶栏加回播放页按钮(MEOW_ICON_QUEUE_MUSIC)→push(ACT_PLAYER), 无音频也生效 - 批④: meowpanel /api/ams/bg 只读端点+前端后台列表页+杀/清复用kill通道 - UI微调: now_playing.c 播放页布局宏下移(NP_COVER_Y 84/NP_BTN_Y 612消底部留白)+歌词页背景统一黑色半透明叠层(弃封面取色底,删 np_draw_lyric_coverbg) - 封面保留: now_playing.c/notif_center.c 空artwork保留上一张已解码封面(防暂停/开歌单致META报空artwork后封面闪没); test_np_cover C2断言更新+mirror同步 0warning;宿主测试 test_np_cover ALL PASS;launcher/ncm/panel 宿主测试无回归。二进制留批量批次未入库
This commit is contained in:
1 parent
b3ce719742
commit
a2aec783a7
15 files changed
+418
-47
No files matched your search
@@ -885,6 +885,105 @@ const { $, $$, LOG_GROUP_NAME, SPARK_MAX, api, apiDownload, applyTheme, authMode
|
||||
});
|
||||
}
|
||||
|
||||
/* ---- 批④ 后台活动页(#/bg):列表 + 行内「杀死」 + 顶栏「一键清后台」(复用 /api/ams/bg 只读 + /api/ams/:pkg/kill) ---- */
|
||||
let bgTimer = null;
|
||||
let bgData = null; // {available,count,apps:[{pkg,name,pid,state,cpu_pct,rss_kb}]}
|
||||
|
||||
function stopBg() { if (bgTimer) { clearInterval(bgTimer); bgTimer = null; } }
|
||||
|
||||
function bgIconHtml(a) {
|
||||
const ch = esc((a.name || a.pkg || '?').charAt(0).toUpperCase());
|
||||
return '<span class="bg-ico">' + ch + '</span>';
|
||||
}
|
||||
|
||||
function renderBgBody(d) {
|
||||
let h = '<div class="page" id="bg-page">';
|
||||
h += '<div class="card"><h3 class="card-title">后台活动 App(meow_amsd bg · 只读)</h3>';
|
||||
if (!d || d.available === false) {
|
||||
h += homeUnavailable();
|
||||
} else {
|
||||
const apps = d.apps || [];
|
||||
if (!apps.length) {
|
||||
h += '<div class="empty">无后台 App</div>';
|
||||
} else {
|
||||
h += '<div class="bg-list">';
|
||||
apps.forEach(a => {
|
||||
const cpu = (a.cpu_pct == null) ? '—' : a.cpu_pct.toFixed(1) + '%';
|
||||
const mem = (a.rss_kb == null) ? '—' : fmtBytes(Number(a.rss_kb) * 1024);
|
||||
const sub = 'CPU ' + cpu + ' · ' + mem + ' · 后台' +
|
||||
(a.pid > 0 ? ' · pid ' + esc(a.pid) : '');
|
||||
h += '<div class="bg-row">' + bgIconHtml(a) +
|
||||
'<div class="bg-info"><div class="bg-name">' + esc(a.name || a.pkg || '未命名') + '</div>' +
|
||||
'<div class="bg-sub">' + sub + '<span class="mono">' + esc(a.pkg) + '</span></div></div>' +
|
||||
'<button class="btn btn-danger" data-bgkill="' + esc(a.pkg) + '">杀死</button></div>';
|
||||
});
|
||||
h += '</div>';
|
||||
}
|
||||
h += '<p class="muted">占用数据读自 /proc/<pid>(与启动器后台管理页同源、同口径);「杀死」经 amsd(require_auth)。CPU 首采样为「—」,轮询后显示真实占用;数据不可得时如实显示「—」,绝不编造。</p>';
|
||||
}
|
||||
h += '</div></div>';
|
||||
return h;
|
||||
}
|
||||
|
||||
async function fetchBgOnce() {
|
||||
const el = $('#bg-page');
|
||||
if (!el || state.route !== 'bg') return;
|
||||
let d = null;
|
||||
try { d = await api('GET', '/api/ams/bg'); }
|
||||
catch (e) {
|
||||
if (state.route === 'bg') el.innerHTML = '<div class="page" id="bg-page">' + emptyState('加载失败:' + errText(e), e.code) + '</div>';
|
||||
const bc = $('#bg-clear'); if (bc) bc.disabled = true;
|
||||
return;
|
||||
}
|
||||
if (state.route !== 'bg') return;
|
||||
bgData = d;
|
||||
el.innerHTML = renderBgBody(d);
|
||||
const bc = $('#bg-clear');
|
||||
if (bc) {
|
||||
const n = (d && d.apps && d.apps.length) ? d.apps.length : 0;
|
||||
bc.disabled = !n;
|
||||
bc.textContent = '一键清后台' + (n ? ' (' + n + ')' : '');
|
||||
}
|
||||
}
|
||||
|
||||
function renderBg() {
|
||||
stopBg();
|
||||
$('#content').innerHTML = '<div class="page" id="bg-page"><p class="placeholder">加载后台 App…</p></div>';
|
||||
fetchBgOnce();
|
||||
bgTimer = setInterval(fetchBgOnce, 4000);
|
||||
}
|
||||
|
||||
async function bgKill(pkg) {
|
||||
const ok = await confirmDlg('结束 App', '确认结束后台 App ' + pkg + '?(SIGTERM 语义)', true);
|
||||
if (!ok) return;
|
||||
try { await api('POST', '/api/ams/' + encodeURIComponent(pkg) + '/kill'); toast('已请求结束 ' + pkg); }
|
||||
catch (e) { toast('结束失败:' + errText(e)); }
|
||||
fetchBgOnce();
|
||||
}
|
||||
|
||||
async function bgClearAll() {
|
||||
const list = (bgData && bgData.apps) ? bgData.apps : [];
|
||||
if (!list.length) { toast('无后台 App 可清'); return; }
|
||||
const ok = await confirmDlg('一键清除后台', '将结束 ' + list.length + ' 个后台 App,确认?(SIGTERM 语义)', true);
|
||||
if (!ok) return;
|
||||
let done = 0, fail = 0;
|
||||
for (const a of list) {
|
||||
try { await api('POST', '/api/ams/' + encodeURIComponent(a.pkg) + '/kill'); done++; }
|
||||
catch (e) { fail++; }
|
||||
}
|
||||
toast('已清 ' + done + ' 个后台 App' + (fail ? ',' + fail + ' 个失败' : ''));
|
||||
fetchBgOnce();
|
||||
}
|
||||
|
||||
function bindBg() {
|
||||
$('#content').addEventListener('click', async function (e) {
|
||||
const kl = e.target.closest('[data-bgkill]');
|
||||
if (kl) { await bgKill(kl.dataset.bgkill); return; }
|
||||
});
|
||||
const bc = $('#bg-clear');
|
||||
if (bc) bc.addEventListener('click', bgClearAll);
|
||||
}
|
||||
|
||||
function stopNet() { if (netTimer) { clearInterval(netTimer); netTimer = null; } }
|
||||
|
||||
function fmtDur(sec) { // 连接寿命(秒级精度)
|
||||
@@ -2376,5 +2475,5 @@ const { $, $$, LOG_GROUP_NAME, SPARK_MAX, api, apiDownload, applyTheme, authMode
|
||||
});
|
||||
}
|
||||
|
||||
Object.assign(MP, { absFor, appInfo, appStatePill, appUninstall, applyScreenDeltaDom, audioCard, audioCtlHtml, audioFlowHtml, audioPortName, audioRouteLabel, batteryCard, batteryCardBody, bindApps, bindAudio, bindFiles, bindFonts, bindHome, bindLogs, bindNet, bindNotif, bindPin, bindPower, bindProc, bindScreen, bindSettings, bindSystem, breakdownCardBody, btCard, createImgFromBlob, crumbHtml, deviceCard, doDownload, ensureScreenCanvas, escSafeAttr, estimateCardBody, eventsBar, fetchAudioOnce, fetchHomeLevel, fetchHomeSystem, fetchNetConns, fetchNetLog, fetchNetOnce, fetchOverviewOnce, fetchPerfOnce, fetchPowerOnce, fetchProcOnce, fetchScreen, fmtDur, fmtFrames, groupName, handleRemoteGesture, healthCard, importFont, importFontPage, installFromFile, installFromPath, joinRel, loadFonts, loadFontsPage, loadPinStatus, logsCrashCard, mkdirFile, navFiles, netBadge, netBannerErr, netCard, netConnsBody, netDnsBody, netIfaceCards, netPolicyCard, netStateCls, netStatusCards, newestStdout, perfCard, pinEdit, pinEditDlg, powerEventsCard, powerHistoryCard, powerPolicyCard, powerProfileLabel, powerSummaryCard, pubBytesCard, remoteBtn, remotePadHtml, remotePointerDown, remotePointerUp, removeFile, renameFile, renderApps, renderAudio, renderBright, renderFiles, renderFontsPage, renderHome, renderHomeCards, renderLogs, renderLogsFiles, renderNet, renderNotif, renderPerf, renderPerfData, renderPower, renderPowerBody, renderProc, renderProcBody, renderScreen, renderSettings, renderSystem, restartScreenPoll, row, screenTap, seedScreenCanvas, segments, sendKey, sendKeyLabel, sendKeyRepeat, sendTheme, setBrightCtl, setPanelPassword, settingControl, srcPill, stopAudio, stopHome, stopNet, stopPerf, stopPower, stopProc, stopScreenPoll, storageCard, svcStatePill, uploadFiles, viewAppStdout, viewLogsCrashTail, volSteps });
|
||||
Object.assign(MP, { absFor, appInfo, appStatePill, appUninstall, applyScreenDeltaDom, audioCard, audioCtlHtml, audioFlowHtml, audioPortName, audioRouteLabel, batteryCard, batteryCardBody, bgClearAll, bgIconHtml, bindBg, bindApps, bindAudio, bindFiles, bindFonts, bindHome, bindLogs, bindNet, bindNotif, bindPin, bindPower, bindProc, bindScreen, bindSettings, bindSystem, breakdownCardBody, btCard, createImgFromBlob, crumbHtml, deviceCard, doDownload, ensureScreenCanvas, escSafeAttr, estimateCardBody, eventsBar, fetchAudioOnce, fetchBgOnce, fetchHomeLevel, fetchHomeSystem, fetchNetConns, fetchNetLog, fetchNetOnce, fetchOverviewOnce, fetchPerfOnce, fetchPowerOnce, fetchProcOnce, fetchScreen, fmtDur, fmtFrames, groupName, handleRemoteGesture, healthCard, importFont, importFontPage, installFromFile, installFromPath, joinRel, loadFonts, loadFontsPage, loadPinStatus, logsCrashCard, mkdirFile, navFiles, netBadge, netBannerErr, netCard, netConnsBody, netDnsBody, netIfaceCards, netPolicyCard, netStateCls, netStatusCards, newestStdout, perfCard, pinEdit, pinEditDlg, powerEventsCard, powerHistoryCard, powerPolicyCard, powerProfileLabel, powerSummaryCard, pubBytesCard, remoteBtn, remotePadHtml, remotePointerDown, remotePointerUp, removeFile, renameFile, renderApps, renderAudio, renderBg, renderBgBody, renderBright, renderFiles, renderFontsPage, renderHome, renderHomeCards, renderLogs, renderLogsFiles, renderNet, renderNotif, renderPerf, renderPerfData, renderPower, renderPowerBody, renderProc, renderProcBody, renderScreen, renderSettings, renderSystem, restartScreenPoll, row, screenTap, seedScreenCanvas, segments, sendKey, sendKeyLabel, sendKeyRepeat, sendTheme, setBrightCtl, setPanelPassword, settingControl, srcPill, stopAudio, stopBg, stopHome, stopNet, stopPerf, stopPower, stopProc, stopScreenPoll, storageCard, svcStatePill, uploadFiles, viewAppStdout, viewLogsCrashTail, volSteps });
|
||||
})();
|
||||
Reference in new issue
Block a user