Skip to content

Commit 048b044

Browse files
numachangclaude
andcommitted
fix(import): Don't fire setLayerBinding for positions whose value already matches
PR zmkfirmware#171's import unconditionally called setLayerBinding for every binding parsed out of the file. Even when the file value was identical to the device's current value (e.g. the user re-imported their own export with no edits), the firmware still flipped its "unsaved changes" flag because *some* setLayerBinding had been called. Save then appeared armed for a no-op flash write, which is both confusing and bad for flash longevity. Diff before calling: fetch keymap.layers once, then per position compare {behaviorId, param1, param2} against the parsed binding. Skip the RPC when they match and count it as `unchanged`. Reword the toast accordingly: - Everything matched: "<file> already matches the device. No changes needed." (info) - Some real updates: "Updated N binding(s) from <file> (M already matched)." with the persist reminder. - Partial / rejected: "Updated N (M already matched), skipped X, rejected Y. …" The `applied` counter is renamed `updated` to match the new semantics. preserved / skipped / failed handling is unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 34aa60d commit 048b044

1 file changed

Lines changed: 31 additions & 6 deletions

File tree

src/App.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,8 @@ function App() {
417417
}
418418
}
419419

420-
let appliedCount = 0;
420+
let updatedCount = 0;
421+
let unchangedCount = 0;
421422
let skippedCount = 0;
422423
let preservedCount = 0;
423424
let failedCount = 0;
@@ -448,6 +449,20 @@ function App() {
448449
const param1 = parsedBinding.params[0] || 0;
449450
const param2 = parsedBinding.params[1] || 0;
450451

452+
// Skip the RPC entirely when the file's value matches the device's
453+
// current value. Sending setLayerBinding for a no-op still flips
454+
// the firmware's "unsaved changes" flag, which would leave Save
455+
// glowing as if there was something to persist when there isn't.
456+
const current = targetLayer.bindings[ki];
457+
if (
458+
current?.behaviorId === behaviorId &&
459+
current?.param1 === param1 &&
460+
current?.param2 === param2
461+
) {
462+
unchangedCount++;
463+
continue;
464+
}
465+
451466
const resp = await call_rpc(conn.conn, {
452467
keymap: {
453468
setLayerBinding: {
@@ -459,7 +474,7 @@ function App() {
459474
});
460475
const code = resp.keymap?.setLayerBinding;
461476
if (code === 0 /* SET_LAYER_BINDING_RESP_OK */) {
462-
appliedCount++;
477+
updatedCount++;
463478
continue;
464479
}
465480

@@ -495,7 +510,7 @@ function App() {
495510
}
496511

497512
console.log(
498-
`[import] applied=${appliedCount} preserved=${preservedCount} skipped=${skippedCount} failed=${failedCount}`
513+
`[import] updated=${updatedCount} unchanged=${unchangedCount} preserved=${preservedCount} skipped=${skippedCount} failed=${failedCount}`
499514
);
500515
if (failedBindings.length > 0) {
501516
console.warn("[import] failed bindings:", failedBindings);
@@ -520,21 +535,31 @@ function App() {
520535
const failedDetail =
521536
failedCount > 0 ? ` Firmware rejected ${failedCount} (see console).` : "";
522537

523-
if (appliedCount === 0 && preservedCount === 0) {
538+
if (
539+
updatedCount === 0 &&
540+
unchangedCount === 0 &&
541+
preservedCount === 0
542+
) {
524543
notify(
525544
"error",
526545
`Import applied no bindings.${unknownDetail}${failedDetail}`
527546
);
547+
} else if (updatedCount === 0 && failedCount === 0 && skippedCount === 0) {
548+
// Everything in the file already matched the device — nothing to save.
549+
notify(
550+
"info",
551+
`${file.name} already matches the device. No changes needed.${readOnlyDetail}`
552+
);
528553
} else if (skippedCount > 0 || failedCount > 0) {
529554
notify(
530555
"warning",
531-
`Imported ${appliedCount}, skipped ${skippedCount}, rejected ${failedCount}.${unknownDetail}${readOnlyDetail}${failedDetail}`,
556+
`Updated ${updatedCount} (${unchangedCount} already matched), skipped ${skippedCount}, rejected ${failedCount}.${unknownDetail}${readOnlyDetail}${failedDetail}`,
532557
{ action: persistReminder }
533558
);
534559
} else {
535560
notify(
536561
"success",
537-
`Imported ${appliedCount} bindings from ${file.name}.${readOnlyDetail}`,
562+
`Updated ${updatedCount} binding${updatedCount === 1 ? "" : "s"} from ${file.name} (${unchangedCount} already matched).${readOnlyDetail}`,
538563
{ action: persistReminder }
539564
);
540565
}

0 commit comments

Comments
 (0)