fix: animated card icon while the card is being initialized (v3.5.5)

The Card reader view showed the static nosim.svg while the status line said
"Card inserted - initializing..." (the header indicator was correct): the
2 s /api/status poll called pysimSetConnected(false) unconditionally in its
not-connected branch, ignoring the equipping / auto-equip-pending state.

- pysimCardStateUpdate(): one `initializing` flag (equipping || card_present
  && auto_equip) now drives both the status text and the icon
  (pysimSetConnected('spin') -> sim_anim.svg), matching the header indicator.
- pysimRefresh() ("Check status"): a reachable server is not an equipped card;
  the icon now follows connected / initializing / none instead of always
  showing the equipped icon.
- card_state.test.js: initializing states -> 'spin', cardless -> false, and
  the four Check-status combinations.

552 frontend / 421 Python green; version 3.5.5; sw cache simple-v258.
This commit is contained in:
2026-09-24 21:41:40 +03:00
parent 719956baee
commit 31ece16ada
5 changed files with 45 additions and 9 deletions
+32 -2
View File
@@ -5,7 +5,7 @@ const path = require('node:path');
const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8');
function extractFunc(src, name) {
function extractFunc(src, name, asyncFn) {
const re = new RegExp('function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{');
const m = re.exec(src);
if (!m) throw new Error('function ' + name + ' not found');
@@ -18,7 +18,7 @@ function extractFunc(src, name) {
if (depth === 0) break;
}
}
return src.slice(m.index, i + 1);
return (asyncFn ? 'async ' : '') + src.slice(m.index, i + 1);
}
let code = 'var _pysimCardStateKey = null;\nvar _pysimCardSession = null;\n'
@@ -31,6 +31,7 @@ let code = 'var _pysimCardStateKey = null;\nvar _pysimCardSession = null;\n'
+ 'var _pysimHeaderIccid = undefined;\nvar _pysimHeaderScp80 = undefined;\nvar _pysimHeaderScp81 = undefined;\n'
+ 'var _cardsAutoIccid = null;\nvar _pysimCardIccid = null;\n';
code += extractFunc(html, 'pysimCardStateUpdate') + '\n';
code += extractFunc(html, 'pysimRefresh', true) + '\n';
code += extractFunc(html, 'pysimAvailabilityState') + '\n';
code += extractFunc(html, 'pysimControlDisabled') + '\n';
code += extractFunc(html, 'pysimProactiveSeqChanged') + '\n';
@@ -130,6 +131,35 @@ test('disconnect with auto-equip shows the initializing message', () => {
assert.ok(el.innerHTML.includes('initializing'), el.innerHTML);
});
test('initializing states show the animated indicator', () => {
for (const extra of [{ card_present: true, equipping: true },
{ card_present: true, auto_equip: true }]) {
const { calls } = setup();
pysimCardStateUpdate(status(extra));
assert.deepStrictEqual(calls.connected, ['spin'], JSON.stringify(extra));
}
});
test('a cardless session without auto-equip shows the static no-card icon', () => {
const { calls } = setup();
pysimCardStateUpdate(status({}));
assert.deepStrictEqual(calls.connected, [false]);
});
test('Check status keeps the icon in step with the card state', async () => {
for (const entry of [
[{ connected: true }, true],
[{ connected: false, card_present: true, equipping: true }, 'spin'],
[{ connected: false, card_present: true, auto_equip: true }, 'spin'],
[{ connected: false }, false],
]) {
const { calls } = setup();
globalThis.pysimFetch = async () => entry[0];
await pysimRefresh();
assert.deepStrictEqual(calls.connected, [entry[1]], JSON.stringify(entry[0]));
}
});
test('unchanged state key does not touch the UI again', () => {
const { el, calls } = setup();
pysimCardStateUpdate(status({ card_session: 7 }));