refactor(companion): shared shutdown steps, SD channel key by secret, fetch race, small UI fixes

- UITaskBase holds what both UIs' shutdown() and low-battery check share:
  the saves before the goodbye sound, the power-down (GPS through its
  provider) and the battery EMA and threshold.
- L2 SD archive: a channel's file is keyed by its secret only, so renaming
  keeps the history; old files are renamed once at boot.
- L2 fetch: abandoning a request and the task finishing it are one critical
  section (it could stay DONE for good); TileCache gets the read-side barrier.
- Text from a repeater or sensor no longer rings on the device (nothing to
  open); a settings switch reads any non-zero value as on; the message
  toast never cuts a letter in half; ui-new's GPS helpers ask UiCore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-12 18:08:31 +02:00
co-authored by Claude Opus 5.5
parent 28d8291e33
commit 01a068be7d
8 changed files with 82 additions and 65 deletions
@@ -391,6 +391,7 @@ static void writeRaw(NodePrefs& p, const Setting& s, int32_t v) {
// (e.g. an auto-off time set on another frontend).
static uint8_t get(const NodePrefs& p, const Setting& s) {
int32_t raw = readRaw(p, s);
if (!s.values && s.count == 2 && !s.option) return raw != 0; // a switch: any non-zero is on (advert_loc_policy 2 from the app)
if (!s.values) return raw >= 0 && raw < s.count ? (uint8_t)raw : 0;
uint8_t best = 0;
int32_t best_d = INT32_MAX;
@@ -205,6 +205,9 @@ public:
const uint8_t* extra, int extra_len, const char* text) override {
// we only want to show text messages on display, not cli data
if (!(txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN)) return;
// Only chats and rooms have a conversation on the device: text from a
// repeater or sensor would ring with nothing to open (the app still gets it).
if (from.type != ADV_TYPE_CHAT && from.type != ADV_TYPE_ROOM) return;
if (from.type == ADV_TYPE_ROOM && _room_unread < _queue_len) _room_unread++;
if (from.type == ADV_TYPE_CHAT) dm_unread.onIncoming(from.id.pub_key); // before the ring insert below
UiEvent& ev = pushMessageArrived(from.type == ADV_TYPE_ROOM ? UIEventType::roomMessage : UIEventType::contactMessage,