feat(train): interval plans, synced and sealed, with an editor and templates (ADR 0030, D42)
Train's server gains the synced `plan` table, a sealed payload alone; the migration `plans` only adds it, its space index and the foreign key to its sync space, and a person's deletion takes it with their space. The app keeps plans as `plan` rows sealed for their row: a name, what they are for, whether a step off target is told, and blocks of steps repeated, each ending after a time, a distance or a lap tap and aiming at a pace, speed, heart rate or zone, or the rower's split, watts or stroke rate. Home's Plans tab lists them, a new one starts from nothing or from a template (4×4 minutes, Tabata, 10×400 m), the editor changes steps on a sheet, and a deletion asks first and can be undone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
fa7680821d
commit
f406ddcc59
1 changed files with 23608 additions and 10 deletions
|
|
@ -53,7 +53,8 @@ void main() {
|
|||
|
||||
test(
|
||||
'deleting a person deletes their space with every key, workout, '
|
||||
"series, profile, day, day's series and night in it, and nobody else's",
|
||||
"series, profile, day, day's series, night and plan in it, and nobody "
|
||||
"else's",
|
||||
() async {
|
||||
for (final person in [alice, bob]) {
|
||||
await _workoutOf(session, person);
|
||||
|
|
@ -66,6 +67,7 @@ void main() {
|
|||
'day',
|
||||
'day_series',
|
||||
'night',
|
||||
'plan',
|
||||
]) {
|
||||
expect(await rowsOf(alice, table), 1, reason: table);
|
||||
}
|
||||
|
|
@ -90,6 +92,7 @@ void main() {
|
|||
'day',
|
||||
'day_series',
|
||||
'night',
|
||||
'plan',
|
||||
]) {
|
||||
expect(await rowsOf(alice, table), 0, reason: table);
|
||||
expect(await rowsOf(bob, table), 1, reason: table);
|
||||
|
|
@ -115,8 +118,8 @@ void main() {
|
|||
/// database wraps it.
|
||||
final _syncDatabases = Expando<OfflineSyncDatabase>();
|
||||
|
||||
/// A key, a workout, a series of it, a profile, a day, a series of it and a
|
||||
/// night in [person]'s personal space, written as their device would through
|
||||
/// A key, a workout, a series of it, a profile, a day, a series of it, a
|
||||
/// night and a plan in [person]'s personal space, written as their device would through
|
||||
/// the sync engine (payloads stand in for sealed ones: the server never reads
|
||||
/// them).
|
||||
Future<void> _workoutOf(Session session, UuidValue person) =>
|
||||
|
|
@ -167,4 +170,9 @@ Future<void> _workoutOf(Session session, UuidValue person) =>
|
|||
Night(keyId: 'p1.0.key', payload: sealed, nonce: sealed),
|
||||
transaction: transaction,
|
||||
);
|
||||
await Plan.db.insertRow(
|
||||
session,
|
||||
Plan(keyId: 'p1.0.key', payload: sealed, nonce: sealed),
|
||||
transaction: transaction,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue