refactor(companion): unify every reboot/power-off through UITask::shutdown()

Settings > Reboot, the phone app's CMD_REBOOT, and the serial CLI's
"reboot" command each hand-rolled their own flush-then-board.reboot()
sequence, so each could drift independently (Settings > Reboot and the
CLI command were both missing the contacts flush added in the previous
commit). Add a pure-virtual AbstractUITask::shutdown(bool restart) --
every UI variant (ui-new/ui-tiny/ui-orig) already implements a method
with this exact signature -- and route all three call sites through it
instead. CMD_FACTORY_RESET intentionally keeps calling board.reboot()
directly: flushing stale in-RAM prefs back out would defeat the format
it just did.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-08 16:03:37 +02:00
co-authored by Claude Sonnet 5
parent a868a60935
commit e3279646f9
3 changed files with 21 additions and 8 deletions
@@ -148,5 +148,12 @@ public:
// added later at the same slot would silently inherit the old one's bot/
// share target or notification melody. Default no-op.
virtual void onChannelRemoved(uint8_t channel_idx) {}
// Single choke point for every controlled power-down (low-battery auto-off,
// long-press power-off, and now every board.reboot() caller too): flush
// prefs/RTC/contacts/trail before the board actually goes down or restarts,
// so no exit path can silently skip a pending write. restart=true reboots,
// false powers off. Every UI variant (ui-new/ui-tiny/ui-orig) implements
// this the same way -- see each's UITask::shutdown().
virtual void shutdown(bool restart = false) = 0;
virtual void loop() = 0;
};
+11 -4
View File
@@ -2380,11 +2380,13 @@ void MyMesh::handleCmdFrame(size_t len) {
writeOKFrame();
}
} else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) {
if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed?
saveContacts();
}
savePrefs(); // flush any on-device setting change not yet persisted -- see UITask::shutdown()'s comment
if (_ui) {
_ui->shutdown(true);
} else {
flushDirtyContacts();
savePrefs();
board.reboot();
}
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
uint8_t reply[11];
int i = 0;
@@ -3192,8 +3194,13 @@ void MyMesh::checkCLIRescueCmd() {
}
} else if (strcmp(cli_command, "reboot") == 0) {
if (_ui) {
_ui->shutdown(true);
} else {
flushDirtyContacts();
savePrefs(); // flush any on-device setting change not yet persisted -- see UITask::shutdown()'s comment
board.reboot(); // doesn't return
}
} else {
Serial.println(" Error: unknown command");
}
@@ -1018,9 +1018,8 @@ public:
return true;
}
if (_selected == REBOOT && enter) {
_task->savePrefsIfDirty(_dirty); // don't lose pending edits across the restart
_task->showAlert("Rebooting...", 800);
board.reboot();
_task->shutdown(true); // flushes prefs/RTC/contacts/trail, then reboots -- single choke point
return true;
}
if (_selected == KEYBOARD_TYPE && p && (left || right || enter)) {