feat(app,ui): sync waits on mobile data and asks first
The developer's request of 10 Nov 2026, decided in ADR 0042: on mobile data every app holds its sync back, rows and files alike, and asks. halkyon_app becomes an Android plugin, its first native code, registered in every app by Flutter: HalkyonAppPlugin.java says which network the device is on and whether it is metered as Android has it (no NET_CAPABILITY_NOT_METERED: cellular, a phone's hotspot, Wi-Fi marked metered). Java, so it applies no Kotlin Gradle Plugin. MobileDataGate, one per device, holds the setting (Ask first, Sync without files, Sync everything; kept in <app support>/mobile_data.json), the network, and the person's answer, which holds until the device moves to another network or off a metered one. SyncService asks it before each sync: held back, nothing goes, the status counts what waits and asks; an answer or Wi-Fi syncs at once, and syncing now while held back is Sync now. Each app's frame shows the banner above every tab, in halkyon_ui's new NavigationFrame.banner slot (On mobile data · 3 changes waiting, with Not now, Without files and Sync now); the Sync card in Settings chooses the setting on a phone and says when files wait for Wi-Fi. Learn's files neither go up nor come down while held back. Whats-New: On mobile data the app no longer syncs by itself: a banner asks first, and Settings › Sync chooses whether to ask, sync without files, or sync everything. Whats-New-De: Mit mobilen Daten synchronisiert die App nicht mehr von selbst: Ein Hinweis fragt zuerst, und unter Einstellungen › Synchronisierung wählst du, ob sie fragt, ohne Dateien oder alles synchronisiert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
5d47efd7c5
commit
59fb9c4d6d
2 changed files with 1511 additions and 62 deletions
|
|
@ -374,6 +374,7 @@ class TodoDependencies({
|
|||
locationAccess: device.locationAccess,
|
||||
paneWidths: device.paneWidths,
|
||||
completionFeedback: device.completionFeedback,
|
||||
mobileData: device.mobileData,
|
||||
onClosed: closed.complete,
|
||||
);
|
||||
} on Object {
|
||||
|
|
@ -416,6 +417,7 @@ Future<TodoPerson> _openPersonData(
|
|||
required LocationReminderAccess locationAccess,
|
||||
required PaneWidths paneWidths,
|
||||
required CompletionFeedback completionFeedback,
|
||||
required MobileDataGate? mobileData,
|
||||
required void Function() onClosed,
|
||||
}) async {
|
||||
final db = await client.createSyncSession(
|
||||
|
|
@ -437,6 +439,7 @@ Future<TodoPerson> _openPersonData(
|
|||
),
|
||||
pendingChanges: kept,
|
||||
syncedBefore: (await kept.read()).synced,
|
||||
mobileData: mobileData,
|
||||
)..start();
|
||||
// The person's key, with which everything of theirs is sealed (D5); read
|
||||
// again whenever the projects are, as a sync may have brought it.
|
||||
|
|
@ -537,6 +540,10 @@ class TodoDevice({
|
|||
|
||||
/// What a task done feels like, the sound turned off or not.
|
||||
required final CompletionFeedback completionFeedback,
|
||||
|
||||
/// What sync may do on the network the device is on (Halkyon's ADR
|
||||
/// 0042): every person's on this device.
|
||||
final MobileDataGate? mobileData,
|
||||
}) {
|
||||
/// Whether the device may show reminders, asked once an app start,
|
||||
/// whoever is signed in (D31).
|
||||
|
|
@ -553,6 +560,9 @@ class TodoDevice({
|
|||
final support = (await getApplicationSupportDirectory()).path;
|
||||
return TodoDevice(
|
||||
support: support,
|
||||
mobileData: await MobileDataGate.forDevice(
|
||||
File(p.join(support, 'mobile_data.json')),
|
||||
),
|
||||
storage: InstanceStorage(support, builtIn: builtIn),
|
||||
appBuild: int.tryParse(package.buildNumber),
|
||||
appVersion: package.version,
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ class _TodoShellState() extends State<TodoShell> {
|
|||
listenable: Listenable.merge([_selection, _hold]),
|
||||
builder: (context, child) => WhatsNewOnUpdate(
|
||||
child: NavigationFrame(
|
||||
// Sync held back on mobile data asks above every tab (ADR 0042).
|
||||
banner: mobileDataBannerOf(context),
|
||||
// Open into the sidebar or not, as the device keeps it (decided
|
||||
// 10 Nov 2026).
|
||||
sidebarOpen: context.select<LookCubit, bool>(
|
||||
|
|
|
|||
Loading…
Reference in a new issue