0.2.3: prepare follow-up fixes and client features (#407, #408, #410, #413, #431, #435, #436, #440, #444)
Add special-target activation without bypassing attack cadence, cooperative card preferences and emotes, skill sound banks, per-operator voice choices, text sizing, install prompts, closed-tab recovery and unanimous setup rerolls. Retain late deployment elapsed time and resolve echo/counter pulses without recursive hook overflow. Independent final review remains pending. Golden: roster-016, roster-035, roster-036, roster-045; boss-boss_1-pair, boss-boss_3-pair, boss-boss_5-pair, boss-boss_7-pair, hidden-boss_9-pair; solo-HARD-9-boosted: Lemuen attack cadence. diy-132: Necras extra activation targets. coop2-NORMAL-14-standins: cooperative purchase preference and simulation fixes. hidden-boss_10-solo: echo pulse FIFO resolution. See DESIGN 28.13-28.24 for assumptions, sources and contributor credit.
This commit is contained in:
1 parent
314564c139
commit
f3658a0dd4
104 files changed
+3674
-741
No files matched your search
@@ -0,0 +1,40 @@
|
||||
// Install prompts are browser-issued, one-use capabilities. No service worker or application cache is installed.
|
||||
export function createPwaInstall(win) {
|
||||
let prompt = null, installed = false;
|
||||
const listeners = new Set();
|
||||
const display = win?.matchMedia?.('(display-mode: standalone), (display-mode: fullscreen)');
|
||||
const available = () => !!prompt && !installed && !display?.matches && !win?.navigator?.standalone;
|
||||
const emit = () => { for (const fn of listeners) fn(available()); };
|
||||
const offer = (event) => {
|
||||
if (installed || display?.matches || win?.navigator?.standalone || typeof event.prompt !== 'function') return;
|
||||
event.preventDefault();
|
||||
prompt = event;
|
||||
emit();
|
||||
};
|
||||
const done = () => { installed = true; prompt = null; emit(); };
|
||||
win?.addEventListener?.('beforeinstallprompt', offer);
|
||||
win?.addEventListener?.('appinstalled', done);
|
||||
display?.addEventListener?.('change', emit);
|
||||
return {
|
||||
available,
|
||||
subscribe(fn) { listeners.add(fn); fn(available()); return () => listeners.delete(fn); },
|
||||
async request() {
|
||||
if (!available()) return false;
|
||||
const event = prompt;
|
||||
prompt = null; // Consume before awaiting: dismissal, rejection and repeated clicks cannot reuse this event.
|
||||
emit();
|
||||
try {
|
||||
const result = await event.prompt();
|
||||
const choice = event.userChoice ? await event.userChoice : result;
|
||||
return choice?.outcome === 'accepted';
|
||||
} catch { return false; }
|
||||
},
|
||||
dispose() {
|
||||
win?.removeEventListener?.('beforeinstallprompt', offer);
|
||||
win?.removeEventListener?.('appinstalled', done);
|
||||
display?.removeEventListener?.('change', emit);
|
||||
prompt = null; listeners.clear();
|
||||
},
|
||||
};
|
||||
}
|
||||
export const pwaInstall = createPwaInstall(globalThis.window);
|
||||
Reference in new issue
Block a user