55 lines
3 KiB
Markdown
55 lines
3 KiB
Markdown
|
|
# ADR 0042: Sync held back on mobile data
|
|||
|
|
|
|||
|
|
- **Status:** decided 10 Nov 2026 by the developer: D1 is their own request, D2 to D5
|
|||
|
|
the agent's recommendations, which they chose. Not built yet.
|
|||
|
|
- **Builds on:** ADR 0014 (halkyon_app, every app's shell, with its `SyncService`).
|
|||
|
|
|
|||
|
|
## Context
|
|||
|
|
|
|||
|
|
Every Halkyon app syncs whenever something changes and on a timer, on whatever network
|
|||
|
|
the device has. Learn's library holds tens of thousands of rows and hundreds of
|
|||
|
|
megabytes of PDFs; a first sync, or an import on another device, can take a phone's
|
|||
|
|
monthly data on the go. The developer asked (10 Nov 2026): *"It should hold back
|
|||
|
|
everything, asking the user whether one wants to sync. Then, give also the option to
|
|||
|
|
exclude files, images etc."*
|
|||
|
|
|
|||
|
|
## Decisions
|
|||
|
|
|
|||
|
|
- **D1.** On mobile data, every app holds back its sync, rows and files alike, and asks
|
|||
|
|
first. Built once, in halkyon_app, around its `SyncService`; nothing an app does on
|
|||
|
|
the device waits on it (local-first as before: what is written is kept and sent
|
|||
|
|
later).
|
|||
|
|
- **D2.** *Mobile data* is a **metered** connection as the operating system says: on
|
|||
|
|
Android its `NET_CAPABILITY_NOT_METERED` missing, which takes in cellular and also a
|
|||
|
|
phone's hotspot or a Wi-Fi network marked metered; read by a few lines of Kotlin in
|
|||
|
|
halkyon_app's plugin code (`connectivity_plus` tells only the kind of network, which
|
|||
|
|
misses the hotspot). iOS: `NWPath.isExpensive`, once the iOS builds ship. Desktops
|
|||
|
|
are never metered.
|
|||
|
|
- **D3.** It asks with a **quiet banner** above the lists, never a dialog: *On mobile
|
|||
|
|
data · 12 changes waiting* with *Sync now*, *Without files* and *Not now*. *Not now*
|
|||
|
|
hides it until something new waits. Pulling a list down to sync is an explicit ask
|
|||
|
|
too, and syncs as *Sync now* would.
|
|||
|
|
- **D4.** An answer **holds until the connection changes**: while the device stays on
|
|||
|
|
this metered network; asked again after Wi-Fi came and went, or when the app starts
|
|||
|
|
again on mobile data.
|
|||
|
|
- **D5.** Settings › Sync has *On mobile data*: **Ask** (the default), **Without files**,
|
|||
|
|
**Everything**. No *Never*: *Not now* holds back already. A device setting (as the
|
|||
|
|
look), not synced: a tablet on Wi-Fi alone and a phone differ.
|
|||
|
|
|
|||
|
|
## What "without files" means
|
|||
|
|
|
|||
|
|
Rows sync; files neither go up nor come down. Each app names its files to halkyon_app
|
|||
|
|
as a queue of its own (Learn's asset uploads and downloads, its PDFs and Jellyfin
|
|||
|
|
covers; Todo's attachments, ADR 0043; Train's maps' tiles stay as they are, fetched
|
|||
|
|
when shown), which `SyncService` pauses and resumes. What is waiting shows in Sync's
|
|||
|
|
card (*3 files waiting for Wi-Fi*).
|
|||
|
|
|
|||
|
|
## To work out when building
|
|||
|
|
|
|||
|
|
- Where the banner sits in each app's frame: halkyon_ui's `NavigationFrame` has no
|
|||
|
|
place for one above every tab yet.
|
|||
|
|
- The sync engine's stream: whether held back means not opening it at all (the
|
|||
|
|
recommendation: nothing goes over the network, not even the handshake) or opening it
|
|||
|
|
and sending nothing.
|
|||
|
|
- Learn's offline reads (b578fcb9) must not wait on a sync held back: the tests of
|
|||
|
|
`ContentKeys` and the gateways already run without one.
|