mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 04:04:21 +02:00
Give the install dialog its own snapshot of installed titles
A Refresh in flight could leave the shared list stale when the dialog opened. The drop now fetches the list itself and hands it to the dialog. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fd0a284942
commit
eb78eba0dc
1 file changed
+9
-9
+9
-9
@@ -1200,8 +1200,10 @@ async function sideloadOne(file, path, isDir = false) {
|
|||||||
await act(`Copy ${file.name} to ~/Downloads`, () => upload(file, "push"));
|
await act(`Copy ${file.name} to ~/Downloads`, () => upload(file, "push"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await loadTitles(); // fresh, so the dialog can say whether this replaces an installed title
|
// Its own fresh list, so the dialog can say whether this replaces an installed title.
|
||||||
const choice = await confirmTitle(r.plan, canPush);
|
let installed = null;
|
||||||
|
try { installed = new Set((await api("/api/titles")).titles.map(t => String(t.id).toLowerCase())); } catch {}
|
||||||
|
const choice = await confirmTitle(r.plan, canPush, installed);
|
||||||
if (choice === "push") {
|
if (choice === "push") {
|
||||||
api("/api/titles", { action: "discard", token: r.token }).catch(() => {});
|
api("/api/titles", { action: "discard", token: r.token }).catch(() => {});
|
||||||
await act(`Copy ${file.name} to ~/Downloads`, () => upload(file, "push"));
|
await act(`Copy ${file.name} to ~/Downloads`, () => upload(file, "push"));
|
||||||
@@ -1210,7 +1212,7 @@ async function sideloadOne(file, path, isDir = false) {
|
|||||||
if (!choice) { api("/api/titles", { action: "discard", token: r.token }).catch(() => {}); return; }
|
if (!choice) { api("/api/titles", { action: "discard", token: r.token }).catch(() => {}); return; }
|
||||||
await installTitle(r.token, choice);
|
await installTitle(r.token, choice);
|
||||||
}
|
}
|
||||||
function confirmTitle(plan, canPush) {
|
function confirmTitle(plan, canPush, installed) { // installed: a Set of lower-case ids, or null if unknown
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const dlg = $("titleDlg");
|
const dlg = $("titleDlg");
|
||||||
$("titlePush").hidden = !canPush;
|
$("titlePush").hidden = !canPush;
|
||||||
@@ -1218,8 +1220,8 @@ function confirmTitle(plan, canPush) {
|
|||||||
$("titleName").value = plan.name;
|
$("titleName").value = plan.name;
|
||||||
const idNote = () => { const id = titleId($("titleName").value);
|
const idNote = () => { const id = titleId($("titleName").value);
|
||||||
$("titleIdNote").textContent = !id ? "Needs some letters or digits"
|
$("titleIdNote").textContent = !id ? "Needs some letters or digits"
|
||||||
: !installedTitles ? `Shows in Steam as ${id}. Couldn't check whether it's installed already; if it is, this replaces it`
|
: !installed ? `Shows in Steam as ${id}. Couldn't check whether it's installed already; if it is, this replaces it`
|
||||||
: installedTitles.has(id.toLowerCase()) ? `Replaces the installed ${id}, and everything in its folder on the Frame`
|
: installed.has(id.toLowerCase()) ? `Replaces the installed ${id}, and everything in its folder on the Frame`
|
||||||
: `Shows in Steam as ${id}`; };
|
: `Shows in Steam as ${id}`; };
|
||||||
$("titleName").oninput = idNote; idNote();
|
$("titleName").oninput = idNote; idNote();
|
||||||
$("titleExe").innerHTML = plan.candidates.map(c =>
|
$("titleExe").innerHTML = plan.candidates.map(c =>
|
||||||
@@ -1276,15 +1278,13 @@ async function installTitle(token, choice) {
|
|||||||
}
|
}
|
||||||
} finally { $("prog").style.display = "none"; loadTitles(); }
|
} finally { $("prog").style.display = "none"; loadTitles(); }
|
||||||
}
|
}
|
||||||
let installedTitles = null; // lower-case ids, so the install dialog can warn before replacing one; null: unknown
|
let titlesSeq = 0; // a slower, older request mustn't overwrite a newer list
|
||||||
let titlesSeq = 0; // a slower, older request mustn't overwrite a newer answer
|
|
||||||
async function loadTitles() {
|
async function loadTitles() {
|
||||||
const seq = ++titlesSeq;
|
const seq = ++titlesSeq;
|
||||||
let list, err;
|
let list, err;
|
||||||
try { list = (await api("/api/titles")).titles; } catch (e) { err = e; }
|
try { list = (await api("/api/titles")).titles; } catch (e) { err = e; }
|
||||||
if (seq !== titlesSeq) return;
|
if (seq !== titlesSeq) return;
|
||||||
if (err) { installedTitles = null; $("titleList").innerHTML = `<div class="sub">${esc(err.message)}</div>`; return; }
|
if (err) { $("titleList").innerHTML = `<div class="sub">${esc(err.message)}</div>`; return; }
|
||||||
installedTitles = new Set(list.map(t => String(t.id).toLowerCase()));
|
|
||||||
$("titleCount").textContent = list.length ? `${list.length}` : "";
|
$("titleCount").textContent = list.length ? `${list.length}` : "";
|
||||||
$("titleList").innerHTML = list.length ? list.map(t => `
|
$("titleList").innerHTML = list.length ? list.map(t => `
|
||||||
<div class="item">
|
<div class="item">
|
||||||
|
|||||||
Reference in new issue
Block a user