feat(train): equipment by place and a plate calculator (ADR 0034)
The places a person trains at (home, a gym), each a sealed, synced `training_place` row with its equipment: bars and handles with their own weight, plates by weight and count, dumbbells and kettlebells, the rest by count, the person's own by name. A new place starts from what a home or a gym usually has. The place last chosen is remembered on the device, never its location. The plate calculator loads each weight both sides alike, the heaviest load not above it with the fewest plates, heavier inside, and over a series of sets picks the loads making the fewest plate moves, listing what comes off and goes on. Equipment is in Settings; strength plans are to build on it. The migration only creates the table, its space index and its cascade to the sync engine's spaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
b7b0b937fe
commit
064b911aa2
47 changed files with 24759 additions and 7 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,936 @@
|
|||
{
|
||||
"__className__": "serverpod.DatabaseDefinition",
|
||||
"schemaVersion": 2,
|
||||
"moduleName": "halkyon_train",
|
||||
"tables": [
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "content_key",
|
||||
"dartName": "ContentKey",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "dataKeyId",
|
||||
"fieldName": "dataKeyId",
|
||||
"columnType": 0,
|
||||
"isNullable": false,
|
||||
"dartType": "String"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "sealedKey",
|
||||
"fieldName": "sealedKey",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "content_key_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "content_key_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "day",
|
||||
"dartName": "Day",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "day_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "day_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "day_series",
|
||||
"dartName": "DaySeries",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "dayId",
|
||||
"fieldName": "dayId",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"dartType": "UuidValue"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "day_series_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "day_series_fk_1",
|
||||
"columns": [
|
||||
"dayId"
|
||||
],
|
||||
"referenceTable": "day",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4,
|
||||
"deferrable": "initiallyDeferred"
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "day_series_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "day_series_day_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "dayId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "night",
|
||||
"dartName": "Night",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "night_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "night_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "plan",
|
||||
"dartName": "Plan",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "plan_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "plan_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "profile",
|
||||
"dartName": "Profile",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "profile_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "profile_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "route",
|
||||
"dartName": "SavedRoute",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "route_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "route_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "training_place",
|
||||
"dartName": "TrainingPlace",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "training_place_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "training_place_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "workout",
|
||||
"dartName": "Workout",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "workout_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "workout_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "workout_series",
|
||||
"dartName": "WorkoutSeries",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "workoutId",
|
||||
"fieldName": "workoutId",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"dartType": "UuidValue"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "workout_series_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "workout_series_fk_1",
|
||||
"columns": [
|
||||
"workoutId"
|
||||
],
|
||||
"referenceTable": "workout",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4,
|
||||
"deferrable": "initiallyDeferred"
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "workout_series_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "workout_series_workout_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "workoutId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
}
|
||||
],
|
||||
"installedModules": [
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "halkyon_base",
|
||||
"version": "20261026140329453-assistant-budgets"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "serverpod",
|
||||
"version": "20260824182259319"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "serverpod_auth_idp",
|
||||
"version": "20260924105404509"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "serverpod_offline_sync",
|
||||
"version": "20260914143806119"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "halkyon_oidc",
|
||||
"version": "20261023180644988"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationVersion",
|
||||
"module": "serverpod_auth_core",
|
||||
"version": "20260924105232991"
|
||||
}
|
||||
],
|
||||
"migrationApiVersion": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"__className__": "serverpod.DatabaseMigration",
|
||||
"actions": [
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationAction",
|
||||
"type": "createTable",
|
||||
"createTable": {
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "training_place",
|
||||
"dartName": "TrainingPlace",
|
||||
"module": "halkyon_train",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "training_place_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "training_place_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"warnings": [],
|
||||
"migrationApiVersion": 1
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ part '20261028164640000-profile/migration.dart';
|
|||
part '20261028181405893-days/migration.dart';
|
||||
part '20261028211508606-plans/migration.dart';
|
||||
part '20261028231042668-routes/migration.dart';
|
||||
part '20261102103211357-training-places/migration.dart';
|
||||
|
||||
/// Migration registry for the client-side database.
|
||||
class MigrationRegistry {
|
||||
|
|
@ -20,6 +21,7 @@ class MigrationRegistry {
|
|||
_Migration20261028181405893_days(),
|
||||
_Migration20261028211508606_plans(),
|
||||
_Migration20261028231042668_routes(),
|
||||
_Migration20261102103211357_training_places(),
|
||||
];
|
||||
|
||||
/// List of all client-side database migration versions.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,672 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:typed_data' as _idt;
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
import 'package:serverpod_database/serverpod_database.dart' as _isd;
|
||||
|
||||
/// A place the person trains at and its equipment (ADR 0034): its name and
|
||||
/// items (bars and handles with their weight, plates and weights by weight
|
||||
/// and count, benches, racks and the person's own), in its sealed payload
|
||||
/// (ADR 0030, D7); the instance sees that it exists, its size and when it
|
||||
/// changed. Changed when edited, the last writer winning. Synced.
|
||||
abstract class TrainingPlace
|
||||
implements _isd.TableRow<_isc.UuidValue?>, _isc.ProtocolSerialization {
|
||||
TrainingPlace._({
|
||||
this.id,
|
||||
this.spaceId,
|
||||
this.keyId,
|
||||
required this.payload,
|
||||
this.nonce,
|
||||
});
|
||||
|
||||
factory TrainingPlace({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) = _TrainingPlaceImpl;
|
||||
|
||||
factory TrainingPlace.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return TrainingPlace(
|
||||
id: jsonSerialization['id'] == null
|
||||
? null
|
||||
: _isc.UuidValueJsonExtension.fromJson(jsonSerialization['id']),
|
||||
spaceId: jsonSerialization['spaceId'] as int?,
|
||||
keyId: jsonSerialization['keyId'] as String?,
|
||||
payload: _isc.ByteDataJsonExtension.fromJson(
|
||||
jsonSerialization['payload'],
|
||||
),
|
||||
nonce: jsonSerialization['nonce'] == null
|
||||
? null
|
||||
: _isc.ByteDataJsonExtension.fromJson(jsonSerialization['nonce']),
|
||||
);
|
||||
}
|
||||
|
||||
static final t = TrainingPlaceTable();
|
||||
|
||||
static const db = TrainingPlaceRepository._();
|
||||
|
||||
@override
|
||||
_isc.UuidValue? id;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
int? spaceId;
|
||||
|
||||
/// The key it is sealed with (ADR 0002's envelope); never null in Train.
|
||||
String? keyId;
|
||||
|
||||
/// The content, sealed: UTF-8 JSON with a `schemaVersion` once opened.
|
||||
_idt.ByteData payload;
|
||||
|
||||
/// The sealing's nonce (ADR 0002's envelope).
|
||||
_idt.ByteData? nonce;
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => t;
|
||||
|
||||
/// Returns a shallow copy of this [TrainingPlace]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
TrainingPlace copyWith({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
_idt.ByteData? payload,
|
||||
_idt.ByteData? nonce,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'TrainingPlace',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'TrainingPlace',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
static TrainingPlaceInclude include() {
|
||||
return TrainingPlaceInclude._();
|
||||
}
|
||||
|
||||
static TrainingPlaceIncludeList includeList({
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
TrainingPlaceInclude? include,
|
||||
}) {
|
||||
return TrainingPlaceIncludeList._(
|
||||
where: where,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
include: include,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _TrainingPlaceImpl extends TrainingPlace {
|
||||
_TrainingPlaceImpl({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) : super._(
|
||||
id: id,
|
||||
spaceId: spaceId,
|
||||
keyId: keyId,
|
||||
payload: payload,
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [TrainingPlace]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
TrainingPlace copyWith({
|
||||
Object? id = _Undefined,
|
||||
Object? spaceId = _Undefined,
|
||||
Object? keyId = _Undefined,
|
||||
_idt.ByteData? payload,
|
||||
Object? nonce = _Undefined,
|
||||
}) {
|
||||
return TrainingPlace(
|
||||
id: id is _isc.UuidValue? ? id : this.id,
|
||||
spaceId: spaceId is int? ? spaceId : this.spaceId,
|
||||
keyId: keyId is String? ? keyId : this.keyId,
|
||||
payload: payload ?? this.payload.clone(),
|
||||
nonce: nonce is _idt.ByteData? ? nonce : this.nonce?.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TrainingPlaceUpdateTable extends _isd.UpdateTable<TrainingPlaceTable> {
|
||||
TrainingPlaceUpdateTable(super.table);
|
||||
|
||||
_isd.ColumnValue<int, int> spaceId(int? value) => _isd.ColumnValue(
|
||||
table.spaceId,
|
||||
value,
|
||||
);
|
||||
|
||||
_isd.ColumnValue<String, String> keyId(String? value) => _isd.ColumnValue(
|
||||
table.keyId,
|
||||
value,
|
||||
);
|
||||
|
||||
_isd.ColumnValue<_idt.ByteData, _idt.ByteData> payload(_idt.ByteData value) =>
|
||||
_isd.ColumnValue(
|
||||
table.payload,
|
||||
value,
|
||||
);
|
||||
|
||||
_isd.ColumnValue<_idt.ByteData, _idt.ByteData> nonce(_idt.ByteData? value) =>
|
||||
_isd.ColumnValue(
|
||||
table.nonce,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
class TrainingPlaceTable extends _isd.Table<_isc.UuidValue?> {
|
||||
TrainingPlaceTable({super.tableRelation})
|
||||
: super(tableName: 'training_place') {
|
||||
updateTable = TrainingPlaceUpdateTable(this);
|
||||
spaceId = _isd.ColumnInt(
|
||||
'spaceId',
|
||||
this,
|
||||
);
|
||||
keyId = _isd.ColumnString(
|
||||
'keyId',
|
||||
this,
|
||||
);
|
||||
payload = _isd.ColumnByteData(
|
||||
'payload',
|
||||
this,
|
||||
);
|
||||
nonce = _isd.ColumnByteData(
|
||||
'nonce',
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
late final TrainingPlaceUpdateTable updateTable;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
late final _isd.ColumnInt spaceId;
|
||||
|
||||
/// The key it is sealed with (ADR 0002's envelope); never null in Train.
|
||||
late final _isd.ColumnString keyId;
|
||||
|
||||
/// The content, sealed: UTF-8 JSON with a `schemaVersion` once opened.
|
||||
late final _isd.ColumnByteData payload;
|
||||
|
||||
/// The sealing's nonce (ADR 0002's envelope).
|
||||
late final _isd.ColumnByteData nonce;
|
||||
|
||||
@override
|
||||
List<_isd.Column> get columns => [
|
||||
id,
|
||||
spaceId,
|
||||
keyId,
|
||||
payload,
|
||||
nonce,
|
||||
];
|
||||
}
|
||||
|
||||
class TrainingPlaceInclude extends _isd.IncludeObject {
|
||||
TrainingPlaceInclude._();
|
||||
|
||||
@override
|
||||
Map<String, _isd.Include?> get includes => {};
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => TrainingPlace.t;
|
||||
}
|
||||
|
||||
class TrainingPlaceIncludeList extends _isd.IncludeList {
|
||||
TrainingPlaceIncludeList._({
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? where,
|
||||
super.limit,
|
||||
super.offset,
|
||||
super.orderBy,
|
||||
super.orderByList,
|
||||
super.include,
|
||||
}) {
|
||||
super.where = where?.call(TrainingPlace.t);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, _isd.Include?> get includes => include?.includes ?? {};
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => TrainingPlace.t;
|
||||
}
|
||||
|
||||
class TrainingPlaceRepository {
|
||||
const TrainingPlaceRepository._();
|
||||
|
||||
/// Returns a list of [TrainingPlace]s matching the given query parameters.
|
||||
///
|
||||
/// Use [where] to specify which items to include in the return value.
|
||||
/// If none is specified, all items will be returned.
|
||||
///
|
||||
/// To specify the order of the items use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// The maximum number of items can be set by [limit]. If no limit is set,
|
||||
/// all items matching the query will be returned.
|
||||
///
|
||||
/// [offset] defines how many items to skip, after which [limit] (or all)
|
||||
/// items are read from the database.
|
||||
///
|
||||
/// ```dart
|
||||
/// var persons = await Persons.db.find(
|
||||
/// session,
|
||||
/// where: (t) => t.lastName.equals('Jones'),
|
||||
/// orderBy: (t) => t.firstName,
|
||||
/// limit: 100,
|
||||
/// );
|
||||
/// ```
|
||||
Future<List<TrainingPlace>> find(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.find<TrainingPlace>(
|
||||
where: where?.call(TrainingPlace.t),
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the first matching [TrainingPlace] matching the given query parameters.
|
||||
///
|
||||
/// Use [where] to specify which items to include in the return value.
|
||||
/// If none is specified, all items will be returned.
|
||||
///
|
||||
/// To specify the order use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// [offset] defines how many items to skip, after which the next one will be picked.
|
||||
///
|
||||
/// ```dart
|
||||
/// var youngestPerson = await Persons.db.findFirstRow(
|
||||
/// session,
|
||||
/// where: (t) => t.lastName.equals('Jones'),
|
||||
/// orderBy: (t) => t.age,
|
||||
/// );
|
||||
/// ```
|
||||
Future<TrainingPlace?> findFirstRow(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? where,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findFirstRow<TrainingPlace>(
|
||||
where: where?.call(TrainingPlace.t),
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Finds a single [TrainingPlace] by its [id] or null if no such row exists.
|
||||
Future<TrainingPlace?> findById(
|
||||
_isd.DatabaseSession session,
|
||||
_isc.UuidValue id, {
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findById<TrainingPlace>(
|
||||
id,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts all [TrainingPlace]s in the list and returns the inserted rows.
|
||||
///
|
||||
/// The returned [TrainingPlace]s will have their `id` fields set.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fails to
|
||||
/// insert, none of the rows will be inserted.
|
||||
///
|
||||
/// If [ignoreConflicts] is set to `true`, rows that conflict with existing
|
||||
/// rows are silently skipped, and only the successfully inserted rows are
|
||||
/// returned.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the inserted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> insert(
|
||||
_isd.DatabaseSession session,
|
||||
List<TrainingPlace> rows, {
|
||||
_isd.Transaction? transaction,
|
||||
bool ignoreConflicts = false,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.insert<TrainingPlace>(
|
||||
rows,
|
||||
transaction: transaction,
|
||||
ignoreConflicts: ignoreConflicts,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts a single [TrainingPlace] and returns the inserted row.
|
||||
///
|
||||
/// The returned [TrainingPlace] will have its `id` field set.
|
||||
Future<TrainingPlace> insertRow(
|
||||
_isd.DatabaseSession session,
|
||||
TrainingPlace row, {
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.insertRow<TrainingPlace>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts all [TrainingPlace]s in the list and returns the resulting rows.
|
||||
///
|
||||
/// If a row conflicts on the given [conflictColumns], the existing row is
|
||||
/// updated with the new values. Otherwise, a new row is inserted.
|
||||
///
|
||||
/// If [updateColumns] is provided, only those columns will be updated on
|
||||
/// conflict. If null, all non-conflict, non-id columns are updated.
|
||||
///
|
||||
/// If [updateWhere] is provided, the update only applies to rows matching the
|
||||
/// given expression. Conflicting rows that don't match are skipped and not
|
||||
/// returned, so the resulting list may be shorter than [rows].
|
||||
///
|
||||
/// The returned [TrainingPlace]s will have their `id` fields set.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fails,
|
||||
/// none of the rows will be affected.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the resulting rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> upsert(
|
||||
_isd.DatabaseSession session,
|
||||
List<TrainingPlace> rows, {
|
||||
required _isd.ColumnSelections<TrainingPlaceTable> conflictColumns,
|
||||
_isd.ColumnSelections<TrainingPlaceTable>? updateColumns,
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? updateWhere,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.upsert<TrainingPlace>(
|
||||
rows,
|
||||
conflictColumns: conflictColumns(TrainingPlace.t),
|
||||
updateColumns: updateColumns?.call(TrainingPlace.t),
|
||||
updateWhere: updateWhere?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts a single [TrainingPlace] and returns the resulting row.
|
||||
///
|
||||
/// If the row conflicts on the given [conflictColumns], the existing row is
|
||||
/// updated. Otherwise, a new row is inserted.
|
||||
///
|
||||
/// If [updateColumns] is provided, only those columns will be updated on
|
||||
/// conflict. If null, all non-conflict, non-id columns are updated.
|
||||
///
|
||||
/// If [updateWhere] is provided, the update only applies when the existing
|
||||
/// row matches the expression. Returns `null` if no row was affected — for
|
||||
/// example when [updateWhere] does not match the conflicting row.
|
||||
///
|
||||
/// The returned [TrainingPlace] will have its `id` field set.
|
||||
Future<TrainingPlace?> upsertRow(
|
||||
_isd.DatabaseSession session,
|
||||
TrainingPlace row, {
|
||||
required _isd.ColumnSelections<TrainingPlaceTable> conflictColumns,
|
||||
_isd.ColumnSelections<TrainingPlaceTable>? updateColumns,
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? updateWhere,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.upsertRow<TrainingPlace>(
|
||||
row,
|
||||
conflictColumns: conflictColumns(TrainingPlace.t),
|
||||
updateColumns: updateColumns?.call(TrainingPlace.t),
|
||||
updateWhere: updateWhere?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [TrainingPlace]s in the list and returns the updated rows. If
|
||||
/// [columns] is provided, only those columns will be updated. Defaults to
|
||||
/// all columns.
|
||||
/// This is an atomic operation, meaning that if one of the rows fails to
|
||||
/// update, none of the rows will be updated.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the updated rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> update(
|
||||
_isd.DatabaseSession session,
|
||||
List<TrainingPlace> rows, {
|
||||
_isd.ColumnSelections<TrainingPlaceTable>? columns,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.update<TrainingPlace>(
|
||||
rows,
|
||||
columns: columns?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [TrainingPlace]. The row needs to have its id set.
|
||||
/// Optionally, a list of [columns] can be provided to only update those
|
||||
/// columns. Defaults to all columns.
|
||||
Future<TrainingPlace> updateRow(
|
||||
_isd.DatabaseSession session,
|
||||
TrainingPlace row, {
|
||||
_isd.ColumnSelections<TrainingPlaceTable>? columns,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateRow<TrainingPlace>(
|
||||
row,
|
||||
columns: columns?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [TrainingPlace] by its [id] with the specified [columnValues].
|
||||
/// Returns the updated row or null if no row with the given id exists.
|
||||
Future<TrainingPlace?> updateById(
|
||||
_isd.DatabaseSession session,
|
||||
_isc.UuidValue id, {
|
||||
required _isd.ColumnValueListBuilder<TrainingPlaceUpdateTable> columnValues,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateById<TrainingPlace>(
|
||||
id,
|
||||
columnValues: columnValues(TrainingPlace.t.updateTable),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [TrainingPlace]s matching the [where] expression with the specified [columnValues].
|
||||
/// Returns the list of updated rows.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the updated rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> updateWhere(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.ColumnValueListBuilder<TrainingPlaceUpdateTable> columnValues,
|
||||
required _isd.WhereExpressionBuilder<TrainingPlaceTable> where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.updateWhere<TrainingPlace>(
|
||||
columnValues: columnValues(TrainingPlace.t.updateTable),
|
||||
where: where(TrainingPlace.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all [TrainingPlace]s in the list and returns the deleted rows.
|
||||
///
|
||||
/// To specify the order of the returned rows use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fail to
|
||||
/// be deleted, none of the rows will be deleted.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the deleted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> delete(
|
||||
_isd.DatabaseSession session,
|
||||
List<TrainingPlace> rows, {
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.delete<TrainingPlace>(
|
||||
rows,
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes a single [TrainingPlace].
|
||||
Future<TrainingPlace> deleteRow(
|
||||
_isd.DatabaseSession session,
|
||||
TrainingPlace row, {
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.deleteRow<TrainingPlace>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all rows matching the [where] expression.
|
||||
///
|
||||
/// To specify the order of the returned rows use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the deleted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<TrainingPlace>> deleteWhere(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.WhereExpressionBuilder<TrainingPlaceTable> where,
|
||||
_isd.OrderByBuilder<TrainingPlaceTable>? orderBy,
|
||||
_isd.OrderByListBuilder<TrainingPlaceTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.deleteWhere<TrainingPlace>(
|
||||
where: where(TrainingPlace.t),
|
||||
orderBy: orderBy?.call(TrainingPlace.t),
|
||||
orderByList: orderByList?.call(TrainingPlace.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Counts the number of rows matching the [where] expression. If omitted,
|
||||
/// will return the count of all rows in the table.
|
||||
Future<int> count(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<TrainingPlaceTable>? where,
|
||||
int? limit,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.count<TrainingPlace>(
|
||||
where: where?.call(TrainingPlace.t),
|
||||
limit: limit,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Acquires row-level locks on [TrainingPlace] rows matching the [where] expression.
|
||||
Future<void> lockRows(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.WhereExpressionBuilder<TrainingPlaceTable> where,
|
||||
required _isd.LockMode lockMode,
|
||||
required _isd.Transaction transaction,
|
||||
_isd.LockBehavior lockBehavior = _isd.LockBehavior.wait,
|
||||
}) async {
|
||||
return session.db.lockRows<TrainingPlace>(
|
||||
where: where(TrainingPlace.t),
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import 'package:serverpod_offline_sync_client/serverpod_offline_sync_client.dart
|
|||
import 'day/day.dart' as _ikmv9f3y;
|
||||
import 'day/day_series.dart' as _ir1ofny6;
|
||||
import 'day/night.dart' as _i17cgxdf;
|
||||
import 'equipment/training_place.dart' as _icbb9j80;
|
||||
import 'firmware/loop_firmware.dart' as _i4qollgq;
|
||||
import 'firmware/loop_firmware_refused.dart' as _ipcwdy0l;
|
||||
import 'map/map_source.dart' as _ikw0qg8x;
|
||||
|
|
@ -48,6 +49,7 @@ import 'workout/workout_series.dart' as _i92mefto;
|
|||
export 'day/day.dart';
|
||||
export 'day/day_series.dart';
|
||||
export 'day/night.dart';
|
||||
export 'equipment/training_place.dart';
|
||||
export 'firmware/loop_firmware.dart';
|
||||
export 'firmware/loop_firmware_refused.dart';
|
||||
export 'map/map_source.dart';
|
||||
|
|
@ -569,6 +571,73 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
],
|
||||
managed: true,
|
||||
),
|
||||
_isd.TableDefinition(
|
||||
name: 'training_place',
|
||||
dartName: 'TrainingPlace',
|
||||
schema: 'public',
|
||||
module: 'halkyon_train',
|
||||
columns: [
|
||||
_isd.ColumnDefinition(
|
||||
name: 'id',
|
||||
columnType: _isd.ColumnType.uuid,
|
||||
isNullable: false,
|
||||
dartType: 'UuidValue?',
|
||||
columnDefault: 'random_v7',
|
||||
),
|
||||
_isd.ColumnDefinition(
|
||||
name: 'spaceId',
|
||||
columnType: _isd.ColumnType.bigint,
|
||||
isNullable: true,
|
||||
dartType: 'int?',
|
||||
),
|
||||
_isd.ColumnDefinition(
|
||||
name: 'keyId',
|
||||
columnType: _isd.ColumnType.text,
|
||||
isNullable: true,
|
||||
dartType: 'String?',
|
||||
),
|
||||
_isd.ColumnDefinition(
|
||||
name: 'payload',
|
||||
columnType: _isd.ColumnType.bytea,
|
||||
isNullable: false,
|
||||
dartType: 'dart:typed_data:ByteData',
|
||||
),
|
||||
_isd.ColumnDefinition(
|
||||
name: 'nonce',
|
||||
columnType: _isd.ColumnType.bytea,
|
||||
isNullable: true,
|
||||
dartType: 'dart:typed_data:ByteData?',
|
||||
),
|
||||
],
|
||||
foreignKeys: [
|
||||
_isd.ForeignKeyDefinition(
|
||||
constraintName: 'training_place_fk_0',
|
||||
columns: ['spaceId'],
|
||||
referenceTable: 'offline_sync_spaces',
|
||||
referenceTableSchema: 'public',
|
||||
referenceColumns: ['id'],
|
||||
onUpdate: _isd.ForeignKeyAction.noAction,
|
||||
onDelete: _isd.ForeignKeyAction.cascade,
|
||||
matchType: null,
|
||||
),
|
||||
],
|
||||
indexes: [
|
||||
_isd.IndexDefinition(
|
||||
indexName: 'training_place_space_idx',
|
||||
tableSpace: null,
|
||||
elements: [
|
||||
_isd.IndexElementDefinition(
|
||||
type: _isd.IndexElementDefinitionType.column,
|
||||
definition: 'spaceId',
|
||||
),
|
||||
],
|
||||
type: 'btree',
|
||||
isUnique: false,
|
||||
isPrimary: false,
|
||||
),
|
||||
],
|
||||
managed: true,
|
||||
),
|
||||
_isd.TableDefinition(
|
||||
name: 'workout',
|
||||
dartName: 'Workout',
|
||||
|
|
@ -791,6 +860,9 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
if (t == _i17cgxdf.Night) {
|
||||
return _i17cgxdf.Night.fromJson(data) as T;
|
||||
}
|
||||
if (t == _icbb9j80.TrainingPlace) {
|
||||
return _icbb9j80.TrainingPlace.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i4qollgq.LoopFirmware) {
|
||||
return _i4qollgq.LoopFirmware.fromJson(data) as T;
|
||||
}
|
||||
|
|
@ -851,6 +923,10 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
if (t == _isc.getType<_i17cgxdf.Night?>()) {
|
||||
return (data != null ? _i17cgxdf.Night.fromJson(data) : null) as T;
|
||||
}
|
||||
if (t == _isc.getType<_icbb9j80.TrainingPlace?>()) {
|
||||
return (data != null ? _icbb9j80.TrainingPlace.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_i4qollgq.LoopFirmware?>()) {
|
||||
return (data != null ? _i4qollgq.LoopFirmware.fromJson(data) : null) as T;
|
||||
}
|
||||
|
|
@ -961,6 +1037,7 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
_ikmv9f3y.Day => 'Day',
|
||||
_ir1ofny6.DaySeries => 'DaySeries',
|
||||
_i17cgxdf.Night => 'Night',
|
||||
_icbb9j80.TrainingPlace => 'TrainingPlace',
|
||||
_i4qollgq.LoopFirmware => 'LoopFirmware',
|
||||
_ipcwdy0l.LoopFirmwareRefused => 'LoopFirmwareRefused',
|
||||
_ikw0qg8x.MapSource => 'MapSource',
|
||||
|
|
@ -1001,6 +1078,8 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
return 'DaySeries';
|
||||
case _i17cgxdf.Night():
|
||||
return 'Night';
|
||||
case _icbb9j80.TrainingPlace():
|
||||
return 'TrainingPlace';
|
||||
case _i4qollgq.LoopFirmware():
|
||||
return 'LoopFirmware';
|
||||
case _ipcwdy0l.LoopFirmwareRefused():
|
||||
|
|
@ -1080,6 +1159,9 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
if (dataClassName == 'Night') {
|
||||
return deserialize<_i17cgxdf.Night>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'TrainingPlace') {
|
||||
return deserialize<_icbb9j80.TrainingPlace>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'LoopFirmware') {
|
||||
return deserialize<_i4qollgq.LoopFirmware>(data['data']);
|
||||
}
|
||||
|
|
@ -1216,6 +1298,8 @@ class Protocol extends _isd.DatabaseSerializationManager {
|
|||
return _ir1ofny6.DaySeries.t;
|
||||
case _i17cgxdf.Night:
|
||||
return _i17cgxdf.Night.t;
|
||||
case _icbb9j80.TrainingPlace:
|
||||
return _icbb9j80.TrainingPlace.t;
|
||||
case _i45prw73.Plan:
|
||||
return _i45prw73.Plan.t;
|
||||
case _imed3x5d.ContentKey:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:serverpod_database/serverpod_database.dart' as _isd;
|
|||
import 'day/day.dart' as _ikmv9f3y;
|
||||
import 'day/day_series.dart' as _ir1ofny6;
|
||||
import 'day/night.dart' as _i17cgxdf;
|
||||
import 'equipment/training_place.dart' as _icbb9j80;
|
||||
import 'plan/plan.dart' as _i45prw73;
|
||||
import 'privacy/content_key.dart' as _imed3x5d;
|
||||
import 'profile/profile.dart' as _ia5j8fch;
|
||||
|
|
@ -32,6 +33,7 @@ final List<_isd.Table> syncTables = [
|
|||
_i45prw73.Plan.t,
|
||||
_ia5j8fch.Profile.t,
|
||||
_i0mgeh8t.SavedRoute.t,
|
||||
_icbb9j80.TrainingPlace.t,
|
||||
_i5b9b17z.Workout.t,
|
||||
_i92mefto.WorkoutSeries.t,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -580,5 +580,59 @@
|
|||
"bodyWeight": "{kg} kg",
|
||||
"bodyResting": "Ruhepuls {bpm}",
|
||||
"bodyMax": "Maximalpuls {bpm}",
|
||||
"homeToday": "Heute"
|
||||
"homeToday": "Heute",
|
||||
|
||||
"equipmentTitle": "Ausrüstung",
|
||||
"equipmentHint": "Wo du trainierst und was es dort gibt",
|
||||
"equipmentEmptyTitle": "Noch keine Orte",
|
||||
"equipmentEmptyHint": "Füge die Orte hinzu, an denen du trainierst, etwa dein Zuhause und dein Studio, mit dem, was es dort gibt. Beginne mit dem, was ein Zuhause oder ein Studio meist hat, oder mit nichts.",
|
||||
"equipmentAddPlace": "Ort hinzufügen",
|
||||
"equipmentItems": "{count, plural, =0{Noch nichts} =1{1 Ausrüstungsstück} other{{count} Ausrüstungsstücke}}",
|
||||
"equipmentChosen": "Hier trainierst du gerade",
|
||||
"equipmentChoose": "Hier trainieren",
|
||||
"equipmentLocked": "Lässt sich auf diesem Gerät nicht öffnen",
|
||||
"placeNewTitle": "Neuer Ort",
|
||||
"placeName": "Name",
|
||||
"placeStartFrom": "Beginnen mit",
|
||||
"placeStartHome": "Zuhause",
|
||||
"placeStartGym": "Studio",
|
||||
"placeStartNothing": "Nichts",
|
||||
"placeDefaultHome": "Zuhause",
|
||||
"placeDefaultGym": "Studio",
|
||||
"placeAdd": "Hinzufügen",
|
||||
"placeRename": "Umbenennen",
|
||||
"placeSave": "Speichern",
|
||||
"placeDelete": "Ort löschen",
|
||||
"placeDeleteMessage": "Der Ort und seine Ausrüstung werden auf all deinen Geräten gelöscht.",
|
||||
"placeAddEquipment": "Ausrüstung hinzufügen",
|
||||
"placeEmptyHint": "Hier ist noch nichts. Füge die Ausrüstung hinzu, die es an diesem Ort gibt.",
|
||||
"equipmentKind": "{kind, select, barbell{Langhantel} ezBar{SZ-Stange} trapBar{Trap Bar} dumbbellHandle{Kurzhantelgriffe} plates{Hantelscheiben} fixedDumbbells{Kurzhanteln} kettlebells{Kettlebells} bench{Bank} rack{Rack} pullUpBar{Klimmzugstange} dipBars{Dipstation} cableMachine{Kabelzug} bands{Widerstandsbänder} other{Eigenes}}",
|
||||
"itemName": "Was es ist",
|
||||
"itemHowMany": "Wie viele",
|
||||
"itemOwnWeight": "Eigengewicht",
|
||||
"itemWeights": "Gewichte",
|
||||
"itemAddWeight": "Gewicht hinzufügen",
|
||||
"itemDone": "Fertig",
|
||||
"itemRemove": "Entfernen",
|
||||
"itemWeightInvalid": "Ein Gewicht in Kilogramm, über 0",
|
||||
"weightKg": "{weight} kg",
|
||||
"weightCount": "{count} × {weight} kg",
|
||||
"plateCalculatorTitle": "Scheibenrechner",
|
||||
"plateCalculatorHint": "Was du auflegst und was sich zwischen den Sätzen ändert",
|
||||
"platePlace": "Ort",
|
||||
"plateBar": "Stange",
|
||||
"plateDumbbellPair": "Zwei Kurzhantelgriffe",
|
||||
"plateTargets": "Gewichte, kg",
|
||||
"plateTargetsHelper": "Eins für jeden Satz, etwa 60, 80, 100",
|
||||
"plateNoPlace": "Füge zuerst einen Ort hinzu, an dem du trainierst, mit seinen Scheiben.",
|
||||
"plateNoBar": "An diesem Ort gibt es nichts, worauf Scheiben passen. Füge eine Langhantel oder Kurzhantelgriffe hinzu.",
|
||||
"plateBelowBar": "Unter den {weight} kg der Stange",
|
||||
"plateShort": "{weight} kg unter deinem Ziel: Näher kommen die Scheiben nicht",
|
||||
"plateSide": "Jede Seite, von innen: {plates}",
|
||||
"plateBarAlone": "Nur die Stange",
|
||||
"plateOff": "Nimm ab: {plates}",
|
||||
"plateOn": "Leg auf: {plates}",
|
||||
"plateNoChange": "Nichts ändert sich",
|
||||
"plateMoves": "{count, plural, =0{Keine Scheibe bewegt sich} =1{1 Scheibe je Seite bewegt sich} other{{count} Scheiben je Seite bewegen sich}}",
|
||||
"plateSet": "Satz {number}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -734,5 +734,72 @@
|
|||
"@bodyResting": {"placeholders": {"bpm": {"type": "int"}}},
|
||||
"bodyMax": "max {bpm} bpm",
|
||||
"@bodyMax": {"placeholders": {"bpm": {"type": "int"}}},
|
||||
"homeToday": "Today"
|
||||
"homeToday": "Today",
|
||||
|
||||
"equipmentTitle": "Equipment",
|
||||
"@equipmentTitle": {"description": "Settings' entry and the screen of the places the person trains at, with what each has (ADR 0034)."},
|
||||
"equipmentHint": "Where you train, and what's there",
|
||||
"equipmentEmptyTitle": "No places yet",
|
||||
"equipmentEmptyHint": "Add the places you train at, such as your home and your gym, with what each has. Start from what a home or a gym usually has, or from nothing.",
|
||||
"equipmentAddPlace": "Add a place",
|
||||
"equipmentItems": "{count, plural, =0{Nothing yet} =1{1 piece of equipment} other{{count} pieces of equipment}}",
|
||||
"@equipmentItems": {"placeholders": {"count": {"type": "int"}}},
|
||||
"equipmentChosen": "Where you train now",
|
||||
"@equipmentChosen": {"description": "Marks the place chosen, which the plate calculator and plans use (ADR 0034, D4)."},
|
||||
"equipmentChoose": "Train here",
|
||||
"equipmentLocked": "Can't be opened on this device",
|
||||
"placeNewTitle": "New place",
|
||||
"placeName": "Name",
|
||||
"placeStartFrom": "Start from",
|
||||
"placeStartHome": "A home",
|
||||
"placeStartGym": "A gym",
|
||||
"placeStartNothing": "Nothing",
|
||||
"placeDefaultHome": "Home",
|
||||
"placeDefaultGym": "Gym",
|
||||
"placeAdd": "Add",
|
||||
"placeRename": "Rename",
|
||||
"placeSave": "Save",
|
||||
"placeDelete": "Delete place",
|
||||
"placeDeleteMessage": "The place and its equipment are deleted on all your devices.",
|
||||
"placeAddEquipment": "Add equipment",
|
||||
"placeEmptyHint": "Nothing here yet. Add the equipment this place has.",
|
||||
"equipmentKind": "{kind, select, barbell{Barbell} ezBar{EZ bar} trapBar{Trap bar} dumbbellHandle{Dumbbell handles} plates{Weight plates} fixedDumbbells{Dumbbells} kettlebells{Kettlebells} bench{Bench} rack{Rack} pullUpBar{Pull-up bar} dipBars{Dip bars} cableMachine{Cable machine} bands{Resistance bands} other{Your own}}",
|
||||
"@equipmentKind": {"placeholders": {"kind": {"type": "String"}}},
|
||||
"itemName": "What it is",
|
||||
"itemHowMany": "How many",
|
||||
"itemOwnWeight": "Its own weight",
|
||||
"itemWeights": "Weights",
|
||||
"itemAddWeight": "Add a weight",
|
||||
"itemDone": "Done",
|
||||
"itemRemove": "Remove",
|
||||
"itemWeightInvalid": "A weight in kilograms, above 0",
|
||||
"weightKg": "{weight} kg",
|
||||
"@weightKg": {"placeholders": {"weight": {"type": "String"}}},
|
||||
"weightCount": "{count} × {weight} kg",
|
||||
"@weightCount": {"placeholders": {"count": {"type": "int"}, "weight": {"type": "String"}}},
|
||||
"plateCalculatorTitle": "Plate calculator",
|
||||
"plateCalculatorHint": "What to load, and what changes between sets",
|
||||
"platePlace": "Place",
|
||||
"plateBar": "Bar",
|
||||
"plateDumbbellPair": "Two dumbbell handles",
|
||||
"plateTargets": "Weights, kg",
|
||||
"plateTargetsHelper": "One for each set, such as 60, 80, 100",
|
||||
"plateNoPlace": "Add a place you train at, with its plates, first.",
|
||||
"plateNoBar": "This place has nothing that takes plates. Add a barbell or dumbbell handles to it.",
|
||||
"plateBelowBar": "Below the bar's {weight} kg",
|
||||
"@plateBelowBar": {"placeholders": {"weight": {"type": "String"}}},
|
||||
"plateShort": "{weight} kg below what you asked for: the plates make no closer weight",
|
||||
"@plateShort": {"placeholders": {"weight": {"type": "String"}}},
|
||||
"plateSide": "Each side, from the inside: {plates}",
|
||||
"@plateSide": {"placeholders": {"plates": {"type": "String"}}},
|
||||
"plateBarAlone": "The bar alone",
|
||||
"plateOff": "Take off {plates}",
|
||||
"@plateOff": {"placeholders": {"plates": {"type": "String"}}},
|
||||
"plateOn": "Put on {plates}",
|
||||
"@plateOn": {"placeholders": {"plates": {"type": "String"}}},
|
||||
"plateNoChange": "Nothing changes",
|
||||
"plateMoves": "{count, plural, =0{No plate moves} =1{1 plate moves on each side} other{{count} plates move on each side}}",
|
||||
"@plateMoves": {"placeholders": {"count": {"type": "int"}}},
|
||||
"plateSet": "Set {number}",
|
||||
"@plateSet": {"placeholders": {"number": {"type": "int"}}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3507,6 +3507,324 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Today'**
|
||||
String get homeToday;
|
||||
|
||||
/// Settings' entry and the screen of the places the person trains at, with what each has (ADR 0034).
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Equipment'**
|
||||
String get equipmentTitle;
|
||||
|
||||
/// No description provided for @equipmentHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Where you train, and what\'s there'**
|
||||
String get equipmentHint;
|
||||
|
||||
/// No description provided for @equipmentEmptyTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'No places yet'**
|
||||
String get equipmentEmptyTitle;
|
||||
|
||||
/// No description provided for @equipmentEmptyHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add the places you train at, such as your home and your gym, with what each has. Start from what a home or a gym usually has, or from nothing.'**
|
||||
String get equipmentEmptyHint;
|
||||
|
||||
/// No description provided for @equipmentAddPlace.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add a place'**
|
||||
String get equipmentAddPlace;
|
||||
|
||||
/// No description provided for @equipmentItems.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =0{Nothing yet} =1{1 piece of equipment} other{{count} pieces of equipment}}'**
|
||||
String equipmentItems(int count);
|
||||
|
||||
/// Marks the place chosen, which the plate calculator and plans use (ADR 0034, D4).
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Where you train now'**
|
||||
String get equipmentChosen;
|
||||
|
||||
/// No description provided for @equipmentChoose.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Train here'**
|
||||
String get equipmentChoose;
|
||||
|
||||
/// No description provided for @equipmentLocked.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Can\'t be opened on this device'**
|
||||
String get equipmentLocked;
|
||||
|
||||
/// No description provided for @placeNewTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'New place'**
|
||||
String get placeNewTitle;
|
||||
|
||||
/// No description provided for @placeName.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Name'**
|
||||
String get placeName;
|
||||
|
||||
/// No description provided for @placeStartFrom.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Start from'**
|
||||
String get placeStartFrom;
|
||||
|
||||
/// No description provided for @placeStartHome.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A home'**
|
||||
String get placeStartHome;
|
||||
|
||||
/// No description provided for @placeStartGym.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A gym'**
|
||||
String get placeStartGym;
|
||||
|
||||
/// No description provided for @placeStartNothing.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Nothing'**
|
||||
String get placeStartNothing;
|
||||
|
||||
/// No description provided for @placeDefaultHome.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Home'**
|
||||
String get placeDefaultHome;
|
||||
|
||||
/// No description provided for @placeDefaultGym.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Gym'**
|
||||
String get placeDefaultGym;
|
||||
|
||||
/// No description provided for @placeAdd.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add'**
|
||||
String get placeAdd;
|
||||
|
||||
/// No description provided for @placeRename.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Rename'**
|
||||
String get placeRename;
|
||||
|
||||
/// No description provided for @placeSave.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Save'**
|
||||
String get placeSave;
|
||||
|
||||
/// No description provided for @placeDelete.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Delete place'**
|
||||
String get placeDelete;
|
||||
|
||||
/// No description provided for @placeDeleteMessage.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The place and its equipment are deleted on all your devices.'**
|
||||
String get placeDeleteMessage;
|
||||
|
||||
/// No description provided for @placeAddEquipment.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add equipment'**
|
||||
String get placeAddEquipment;
|
||||
|
||||
/// No description provided for @placeEmptyHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Nothing here yet. Add the equipment this place has.'**
|
||||
String get placeEmptyHint;
|
||||
|
||||
/// No description provided for @equipmentKind.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{kind, select, barbell{Barbell} ezBar{EZ bar} trapBar{Trap bar} dumbbellHandle{Dumbbell handles} plates{Weight plates} fixedDumbbells{Dumbbells} kettlebells{Kettlebells} bench{Bench} rack{Rack} pullUpBar{Pull-up bar} dipBars{Dip bars} cableMachine{Cable machine} bands{Resistance bands} other{Your own}}'**
|
||||
String equipmentKind(String kind);
|
||||
|
||||
/// No description provided for @itemName.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'What it is'**
|
||||
String get itemName;
|
||||
|
||||
/// No description provided for @itemHowMany.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'How many'**
|
||||
String get itemHowMany;
|
||||
|
||||
/// No description provided for @itemOwnWeight.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Its own weight'**
|
||||
String get itemOwnWeight;
|
||||
|
||||
/// No description provided for @itemWeights.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Weights'**
|
||||
String get itemWeights;
|
||||
|
||||
/// No description provided for @itemAddWeight.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add a weight'**
|
||||
String get itemAddWeight;
|
||||
|
||||
/// No description provided for @itemDone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Done'**
|
||||
String get itemDone;
|
||||
|
||||
/// No description provided for @itemRemove.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Remove'**
|
||||
String get itemRemove;
|
||||
|
||||
/// No description provided for @itemWeightInvalid.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'A weight in kilograms, above 0'**
|
||||
String get itemWeightInvalid;
|
||||
|
||||
/// No description provided for @weightKg.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{weight} kg'**
|
||||
String weightKg(String weight);
|
||||
|
||||
/// No description provided for @weightCount.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count} × {weight} kg'**
|
||||
String weightCount(int count, String weight);
|
||||
|
||||
/// No description provided for @plateCalculatorTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Plate calculator'**
|
||||
String get plateCalculatorTitle;
|
||||
|
||||
/// No description provided for @plateCalculatorHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'What to load, and what changes between sets'**
|
||||
String get plateCalculatorHint;
|
||||
|
||||
/// No description provided for @platePlace.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Place'**
|
||||
String get platePlace;
|
||||
|
||||
/// No description provided for @plateBar.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Bar'**
|
||||
String get plateBar;
|
||||
|
||||
/// No description provided for @plateDumbbellPair.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Two dumbbell handles'**
|
||||
String get plateDumbbellPair;
|
||||
|
||||
/// No description provided for @plateTargets.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Weights, kg'**
|
||||
String get plateTargets;
|
||||
|
||||
/// No description provided for @plateTargetsHelper.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'One for each set, such as 60, 80, 100'**
|
||||
String get plateTargetsHelper;
|
||||
|
||||
/// No description provided for @plateNoPlace.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Add a place you train at, with its plates, first.'**
|
||||
String get plateNoPlace;
|
||||
|
||||
/// No description provided for @plateNoBar.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This place has nothing that takes plates. Add a barbell or dumbbell handles to it.'**
|
||||
String get plateNoBar;
|
||||
|
||||
/// No description provided for @plateBelowBar.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Below the bar\'s {weight} kg'**
|
||||
String plateBelowBar(String weight);
|
||||
|
||||
/// No description provided for @plateShort.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{weight} kg below what you asked for: the plates make no closer weight'**
|
||||
String plateShort(String weight);
|
||||
|
||||
/// No description provided for @plateSide.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Each side, from the inside: {plates}'**
|
||||
String plateSide(String plates);
|
||||
|
||||
/// No description provided for @plateBarAlone.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The bar alone'**
|
||||
String get plateBarAlone;
|
||||
|
||||
/// No description provided for @plateOff.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Take off {plates}'**
|
||||
String plateOff(String plates);
|
||||
|
||||
/// No description provided for @plateOn.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Put on {plates}'**
|
||||
String plateOn(String plates);
|
||||
|
||||
/// No description provided for @plateNoChange.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Nothing changes'**
|
||||
String get plateNoChange;
|
||||
|
||||
/// No description provided for @plateMoves.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =0{No plate moves} =1{1 plate moves on each side} other{{count} plates move on each side}}'**
|
||||
String plateMoves(int count);
|
||||
|
||||
/// No description provided for @plateSet.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Set {number}'**
|
||||
String plateSet(int number);
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -2112,4 +2112,224 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get homeToday => 'Heute';
|
||||
|
||||
@override
|
||||
String get equipmentTitle => 'Ausrüstung';
|
||||
|
||||
@override
|
||||
String get equipmentHint => 'Wo du trainierst und was es dort gibt';
|
||||
|
||||
@override
|
||||
String get equipmentEmptyTitle => 'Noch keine Orte';
|
||||
|
||||
@override
|
||||
String get equipmentEmptyHint =>
|
||||
'Füge die Orte hinzu, an denen du trainierst, etwa dein Zuhause und dein Studio, mit dem, was es dort gibt. Beginne mit dem, was ein Zuhause oder ein Studio meist hat, oder mit nichts.';
|
||||
|
||||
@override
|
||||
String get equipmentAddPlace => 'Ort hinzufügen';
|
||||
|
||||
@override
|
||||
String equipmentItems(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count Ausrüstungsstücke',
|
||||
one: '1 Ausrüstungsstück',
|
||||
zero: 'Noch nichts',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get equipmentChosen => 'Hier trainierst du gerade';
|
||||
|
||||
@override
|
||||
String get equipmentChoose => 'Hier trainieren';
|
||||
|
||||
@override
|
||||
String get equipmentLocked => 'Lässt sich auf diesem Gerät nicht öffnen';
|
||||
|
||||
@override
|
||||
String get placeNewTitle => 'Neuer Ort';
|
||||
|
||||
@override
|
||||
String get placeName => 'Name';
|
||||
|
||||
@override
|
||||
String get placeStartFrom => 'Beginnen mit';
|
||||
|
||||
@override
|
||||
String get placeStartHome => 'Zuhause';
|
||||
|
||||
@override
|
||||
String get placeStartGym => 'Studio';
|
||||
|
||||
@override
|
||||
String get placeStartNothing => 'Nichts';
|
||||
|
||||
@override
|
||||
String get placeDefaultHome => 'Zuhause';
|
||||
|
||||
@override
|
||||
String get placeDefaultGym => 'Studio';
|
||||
|
||||
@override
|
||||
String get placeAdd => 'Hinzufügen';
|
||||
|
||||
@override
|
||||
String get placeRename => 'Umbenennen';
|
||||
|
||||
@override
|
||||
String get placeSave => 'Speichern';
|
||||
|
||||
@override
|
||||
String get placeDelete => 'Ort löschen';
|
||||
|
||||
@override
|
||||
String get placeDeleteMessage =>
|
||||
'Der Ort und seine Ausrüstung werden auf all deinen Geräten gelöscht.';
|
||||
|
||||
@override
|
||||
String get placeAddEquipment => 'Ausrüstung hinzufügen';
|
||||
|
||||
@override
|
||||
String get placeEmptyHint =>
|
||||
'Hier ist noch nichts. Füge die Ausrüstung hinzu, die es an diesem Ort gibt.';
|
||||
|
||||
@override
|
||||
String equipmentKind(String kind) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
kind,
|
||||
{
|
||||
'barbell': 'Langhantel',
|
||||
'ezBar': 'SZ-Stange',
|
||||
'trapBar': 'Trap Bar',
|
||||
'dumbbellHandle': 'Kurzhantelgriffe',
|
||||
'plates': 'Hantelscheiben',
|
||||
'fixedDumbbells': 'Kurzhanteln',
|
||||
'kettlebells': 'Kettlebells',
|
||||
'bench': 'Bank',
|
||||
'rack': 'Rack',
|
||||
'pullUpBar': 'Klimmzugstange',
|
||||
'dipBars': 'Dipstation',
|
||||
'cableMachine': 'Kabelzug',
|
||||
'bands': 'Widerstandsbänder',
|
||||
'other': 'Eigenes',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get itemName => 'Was es ist';
|
||||
|
||||
@override
|
||||
String get itemHowMany => 'Wie viele';
|
||||
|
||||
@override
|
||||
String get itemOwnWeight => 'Eigengewicht';
|
||||
|
||||
@override
|
||||
String get itemWeights => 'Gewichte';
|
||||
|
||||
@override
|
||||
String get itemAddWeight => 'Gewicht hinzufügen';
|
||||
|
||||
@override
|
||||
String get itemDone => 'Fertig';
|
||||
|
||||
@override
|
||||
String get itemRemove => 'Entfernen';
|
||||
|
||||
@override
|
||||
String get itemWeightInvalid => 'Ein Gewicht in Kilogramm, über 0';
|
||||
|
||||
@override
|
||||
String weightKg(String weight) {
|
||||
return '$weight kg';
|
||||
}
|
||||
|
||||
@override
|
||||
String weightCount(int count, String weight) {
|
||||
return '$count × $weight kg';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateCalculatorTitle => 'Scheibenrechner';
|
||||
|
||||
@override
|
||||
String get plateCalculatorHint =>
|
||||
'Was du auflegst und was sich zwischen den Sätzen ändert';
|
||||
|
||||
@override
|
||||
String get platePlace => 'Ort';
|
||||
|
||||
@override
|
||||
String get plateBar => 'Stange';
|
||||
|
||||
@override
|
||||
String get plateDumbbellPair => 'Zwei Kurzhantelgriffe';
|
||||
|
||||
@override
|
||||
String get plateTargets => 'Gewichte, kg';
|
||||
|
||||
@override
|
||||
String get plateTargetsHelper => 'Eins für jeden Satz, etwa 60, 80, 100';
|
||||
|
||||
@override
|
||||
String get plateNoPlace =>
|
||||
'Füge zuerst einen Ort hinzu, an dem du trainierst, mit seinen Scheiben.';
|
||||
|
||||
@override
|
||||
String get plateNoBar =>
|
||||
'An diesem Ort gibt es nichts, worauf Scheiben passen. Füge eine Langhantel oder Kurzhantelgriffe hinzu.';
|
||||
|
||||
@override
|
||||
String plateBelowBar(String weight) {
|
||||
return 'Unter den $weight kg der Stange';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateShort(String weight) {
|
||||
return '$weight kg unter deinem Ziel: Näher kommen die Scheiben nicht';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateSide(String plates) {
|
||||
return 'Jede Seite, von innen: $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateBarAlone => 'Nur die Stange';
|
||||
|
||||
@override
|
||||
String plateOff(String plates) {
|
||||
return 'Nimm ab: $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateOn(String plates) {
|
||||
return 'Leg auf: $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateNoChange => 'Nichts ändert sich';
|
||||
|
||||
@override
|
||||
String plateMoves(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count Scheiben je Seite bewegen sich',
|
||||
one: '1 Scheibe je Seite bewegt sich',
|
||||
zero: 'Keine Scheibe bewegt sich',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateSet(int number) {
|
||||
return 'Satz $number';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2100,6 +2100,226 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get homeToday => 'Today';
|
||||
|
||||
@override
|
||||
String get equipmentTitle => 'Equipment';
|
||||
|
||||
@override
|
||||
String get equipmentHint => 'Where you train, and what\'s there';
|
||||
|
||||
@override
|
||||
String get equipmentEmptyTitle => 'No places yet';
|
||||
|
||||
@override
|
||||
String get equipmentEmptyHint =>
|
||||
'Add the places you train at, such as your home and your gym, with what each has. Start from what a home or a gym usually has, or from nothing.';
|
||||
|
||||
@override
|
||||
String get equipmentAddPlace => 'Add a place';
|
||||
|
||||
@override
|
||||
String equipmentItems(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count pieces of equipment',
|
||||
one: '1 piece of equipment',
|
||||
zero: 'Nothing yet',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get equipmentChosen => 'Where you train now';
|
||||
|
||||
@override
|
||||
String get equipmentChoose => 'Train here';
|
||||
|
||||
@override
|
||||
String get equipmentLocked => 'Can\'t be opened on this device';
|
||||
|
||||
@override
|
||||
String get placeNewTitle => 'New place';
|
||||
|
||||
@override
|
||||
String get placeName => 'Name';
|
||||
|
||||
@override
|
||||
String get placeStartFrom => 'Start from';
|
||||
|
||||
@override
|
||||
String get placeStartHome => 'A home';
|
||||
|
||||
@override
|
||||
String get placeStartGym => 'A gym';
|
||||
|
||||
@override
|
||||
String get placeStartNothing => 'Nothing';
|
||||
|
||||
@override
|
||||
String get placeDefaultHome => 'Home';
|
||||
|
||||
@override
|
||||
String get placeDefaultGym => 'Gym';
|
||||
|
||||
@override
|
||||
String get placeAdd => 'Add';
|
||||
|
||||
@override
|
||||
String get placeRename => 'Rename';
|
||||
|
||||
@override
|
||||
String get placeSave => 'Save';
|
||||
|
||||
@override
|
||||
String get placeDelete => 'Delete place';
|
||||
|
||||
@override
|
||||
String get placeDeleteMessage =>
|
||||
'The place and its equipment are deleted on all your devices.';
|
||||
|
||||
@override
|
||||
String get placeAddEquipment => 'Add equipment';
|
||||
|
||||
@override
|
||||
String get placeEmptyHint =>
|
||||
'Nothing here yet. Add the equipment this place has.';
|
||||
|
||||
@override
|
||||
String equipmentKind(String kind) {
|
||||
String _temp0 = intl.Intl.selectLogic(
|
||||
kind,
|
||||
{
|
||||
'barbell': 'Barbell',
|
||||
'ezBar': 'EZ bar',
|
||||
'trapBar': 'Trap bar',
|
||||
'dumbbellHandle': 'Dumbbell handles',
|
||||
'plates': 'Weight plates',
|
||||
'fixedDumbbells': 'Dumbbells',
|
||||
'kettlebells': 'Kettlebells',
|
||||
'bench': 'Bench',
|
||||
'rack': 'Rack',
|
||||
'pullUpBar': 'Pull-up bar',
|
||||
'dipBars': 'Dip bars',
|
||||
'cableMachine': 'Cable machine',
|
||||
'bands': 'Resistance bands',
|
||||
'other': 'Your own',
|
||||
},
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get itemName => 'What it is';
|
||||
|
||||
@override
|
||||
String get itemHowMany => 'How many';
|
||||
|
||||
@override
|
||||
String get itemOwnWeight => 'Its own weight';
|
||||
|
||||
@override
|
||||
String get itemWeights => 'Weights';
|
||||
|
||||
@override
|
||||
String get itemAddWeight => 'Add a weight';
|
||||
|
||||
@override
|
||||
String get itemDone => 'Done';
|
||||
|
||||
@override
|
||||
String get itemRemove => 'Remove';
|
||||
|
||||
@override
|
||||
String get itemWeightInvalid => 'A weight in kilograms, above 0';
|
||||
|
||||
@override
|
||||
String weightKg(String weight) {
|
||||
return '$weight kg';
|
||||
}
|
||||
|
||||
@override
|
||||
String weightCount(int count, String weight) {
|
||||
return '$count × $weight kg';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateCalculatorTitle => 'Plate calculator';
|
||||
|
||||
@override
|
||||
String get plateCalculatorHint =>
|
||||
'What to load, and what changes between sets';
|
||||
|
||||
@override
|
||||
String get platePlace => 'Place';
|
||||
|
||||
@override
|
||||
String get plateBar => 'Bar';
|
||||
|
||||
@override
|
||||
String get plateDumbbellPair => 'Two dumbbell handles';
|
||||
|
||||
@override
|
||||
String get plateTargets => 'Weights, kg';
|
||||
|
||||
@override
|
||||
String get plateTargetsHelper => 'One for each set, such as 60, 80, 100';
|
||||
|
||||
@override
|
||||
String get plateNoPlace =>
|
||||
'Add a place you train at, with its plates, first.';
|
||||
|
||||
@override
|
||||
String get plateNoBar =>
|
||||
'This place has nothing that takes plates. Add a barbell or dumbbell handles to it.';
|
||||
|
||||
@override
|
||||
String plateBelowBar(String weight) {
|
||||
return 'Below the bar\'s $weight kg';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateShort(String weight) {
|
||||
return '$weight kg below what you asked for: the plates make no closer weight';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateSide(String plates) {
|
||||
return 'Each side, from the inside: $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateBarAlone => 'The bar alone';
|
||||
|
||||
@override
|
||||
String plateOff(String plates) {
|
||||
return 'Take off $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateOn(String plates) {
|
||||
return 'Put on $plates';
|
||||
}
|
||||
|
||||
@override
|
||||
String get plateNoChange => 'Nothing changes';
|
||||
|
||||
@override
|
||||
String plateMoves(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count plates move on each side',
|
||||
one: '1 plate moves on each side',
|
||||
zero: 'No plate moves',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String plateSet(int number) {
|
||||
return 'Set $number';
|
||||
}
|
||||
}
|
||||
|
||||
/// The translations for English, as used in the United Kingdom (`en_GB`).
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ import 'package:halkyon_train_flutter/src/core/privacy/sync_content_key_gateway.
|
|||
import 'package:halkyon_train_flutter/src/core/privacy/train_keys.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/day/data/day_repository.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/day/data/sync_day_gateway.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/chosen_place_store.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/place_repository.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/sync_place_gateway.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/health/data/android_health_platform.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/health/data/health_connect.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/health/data/health_store.dart';
|
||||
|
|
@ -82,6 +85,13 @@ class TrainPerson(
|
|||
/// Their routes (D44), sealed and synced.
|
||||
required final RouteRepository routes,
|
||||
|
||||
/// The places they train at with their equipment (ADR 0034), sealed and
|
||||
/// synced.
|
||||
required final PlaceRepository places,
|
||||
|
||||
/// The place last chosen on this device (ADR 0034, D4).
|
||||
required final ChosenPlaceStore chosenPlace,
|
||||
|
||||
/// The instance's planning of routes (D44).
|
||||
required final RoutingGateway routing,
|
||||
|
||||
|
|
@ -403,6 +413,7 @@ Future<TrainPerson> _openPersonData(
|
|||
final days = DayRepository(SyncDayGateway(db, sync), keys);
|
||||
final plans = PlanRepository(SyncPlanGateway(db, sync), keys);
|
||||
final routes = RouteRepository(SyncRouteGateway(db, sync), keys);
|
||||
final places = PlaceRepository(SyncPlaceGateway(db, sync), keys);
|
||||
final maps = MapSourceRepository(
|
||||
ServerpodMapSourceGateway(client),
|
||||
kept: File(p.join(folder.path, 'map_source.json')),
|
||||
|
|
@ -460,6 +471,8 @@ Future<TrainPerson> _openPersonData(
|
|||
days: days,
|
||||
plans: plans,
|
||||
routes: routes,
|
||||
places: places,
|
||||
chosenPlace: ChosenPlaceStore(File(p.join(folder.path, 'place.json'))),
|
||||
routing: ServerpodRoutingGateway(client),
|
||||
placeSearch: ServerpodPlaceSearchGateway(client),
|
||||
maps: maps,
|
||||
|
|
@ -496,6 +509,7 @@ Future<TrainPerson> _openPersonData(
|
|||
await days.dispose();
|
||||
await plans.dispose();
|
||||
await routes.dispose();
|
||||
await places.dispose();
|
||||
await sync.dispose();
|
||||
await db.close();
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/chosen_place_store.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/place_repository.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/model/equipment.dart';
|
||||
|
||||
/// The places the person trains at (ADR 0034), by name, those this device
|
||||
/// can't open last, read again whenever they change, here or on another
|
||||
/// device; and the one chosen, remembered on this device (D4): the one last
|
||||
/// chosen while it is there, else the first.
|
||||
class PlacesCubit(
|
||||
final PlaceRepository _places,
|
||||
final ChosenPlaceStore _chosen,
|
||||
) extends Cubit<PlacesState> {
|
||||
this : super(const PlacesState());
|
||||
|
||||
StreamSubscription<void>? _changes;
|
||||
|
||||
Future<void> open() async {
|
||||
_changes = _places.changes.listen((_) => unawaited(_read()));
|
||||
await _read();
|
||||
}
|
||||
|
||||
/// Keeps a new place, chosen from then on, and returns its id.
|
||||
Future<String> add(PlaceContent content) async {
|
||||
final id = await _places.save(content);
|
||||
await choose(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
Future<void> update(String id, PlaceContent content) =>
|
||||
_places.update(id, content);
|
||||
|
||||
Future<void> delete(String id) => _places.delete(id);
|
||||
|
||||
Future<void> choose(String id) async {
|
||||
await _chosen.write(id);
|
||||
if (!isClosed) {
|
||||
emit(state._with(chosen: id));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _read() async {
|
||||
final all = await _places.all();
|
||||
final opened =
|
||||
[
|
||||
for (final place in all)
|
||||
if (place.content != null) place,
|
||||
]..sort(
|
||||
(a, b) => a.content!.name.toLowerCase().compareTo(
|
||||
b.content!.name.toLowerCase(),
|
||||
),
|
||||
);
|
||||
if (!isClosed) {
|
||||
emit(
|
||||
state._with(
|
||||
all: [
|
||||
...opened,
|
||||
for (final place in all)
|
||||
if (place.content == null) place,
|
||||
],
|
||||
chosen: state._chosen ?? _chosen.read(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _changes?.cancel();
|
||||
await super.close();
|
||||
}
|
||||
}
|
||||
|
||||
final class const PlacesState({
|
||||
final bool loaded = false,
|
||||
final List<StoredPlace> all = const [],
|
||||
final String? _chosen,
|
||||
}) with Equatable {
|
||||
/// The place chosen: the one last chosen while it opens here, else the
|
||||
/// first that does; null while none does.
|
||||
StoredPlace? get chosen {
|
||||
final open = [
|
||||
for (final place in all)
|
||||
if (place.content != null) place,
|
||||
];
|
||||
return open.where((place) => place.id == _chosen).firstOrNull ??
|
||||
open.firstOrNull;
|
||||
}
|
||||
|
||||
PlacesState _with({List<StoredPlace>? all, String? chosen}) => PlacesState(
|
||||
loaded: loaded || all != null,
|
||||
all: all ?? this.all,
|
||||
chosen: chosen ?? _chosen,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [loaded, all, _chosen];
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
/// The place last chosen on this device (ADR 0034, D4), in the person's
|
||||
/// `place.json`, never synced: where a phone is is the phone's. Without a
|
||||
/// file (widget tests), kept in memory.
|
||||
class ChosenPlaceStore([final File? _file]) {
|
||||
String? _memory;
|
||||
|
||||
String? read() {
|
||||
final file = _file;
|
||||
if (file == null) {
|
||||
return _memory;
|
||||
}
|
||||
try {
|
||||
return switch (jsonDecode(file.readAsStringSync())) {
|
||||
{'id': final String id} => id,
|
||||
_ => null,
|
||||
};
|
||||
} on Object {
|
||||
// None yet, or unreadable: as if none was chosen.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> write(String id) async {
|
||||
final file = _file;
|
||||
if (file == null) {
|
||||
_memory = id;
|
||||
return;
|
||||
}
|
||||
await file.writeAsString(jsonEncode({'id': id}), flush: true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import 'package:halkyon_app/halkyon_app.dart';
|
||||
|
||||
/// A `training_place` row as kept: its id and its envelope, sealed (ADR 0030,
|
||||
/// D7).
|
||||
typedef PlaceRow = ({String id, Envelope envelope});
|
||||
|
||||
/// Where the person's training places are kept: their synced
|
||||
/// `training_place` rows (ADR 0034). The repository seals and opens;
|
||||
/// this only keeps.
|
||||
abstract interface class PlaceGateway() {
|
||||
Future<List<PlaceRow>> places();
|
||||
|
||||
Future<void> insert(PlaceRow place);
|
||||
|
||||
/// Replaces the place [id]'s envelope (an edit); nothing for one gone.
|
||||
Future<void> update(String id, Envelope envelope);
|
||||
|
||||
/// Deletes the place [id], its payload blanked first (ADR 0002, rule 2).
|
||||
Future<void> delete(String id);
|
||||
|
||||
/// Fires when a sync brought changes from the person's other devices.
|
||||
Stream<void> get remoteChanges;
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/model/equipment.dart';
|
||||
|
||||
/// The schema of a place's payload this app writes and reads.
|
||||
const placeSchemaVersion = 1;
|
||||
|
||||
/// [content] as its row's payload, before sealing (ADR 0034): UTF-8 JSON,
|
||||
/// every weight in grams, what is counted by weight as `[grams, count]`
|
||||
/// pairs, the heaviest first.
|
||||
ByteData encodePlace(PlaceContent content) => ByteData.sublistView(
|
||||
Uint8List.fromList(
|
||||
utf8.encode(
|
||||
jsonEncode({
|
||||
'schemaVersion': placeSchemaVersion,
|
||||
'name': content.name,
|
||||
'items': [
|
||||
for (final item in content.items)
|
||||
{
|
||||
'kind': item.kind.name,
|
||||
'name': ?item.name,
|
||||
'count': item.count,
|
||||
'grams': ?item.grams,
|
||||
if (item.weights.isNotEmpty)
|
||||
'weights': [
|
||||
for (final grams
|
||||
in item.weights.keys.toList()
|
||||
..sort((a, b) => b.compareTo(a)))
|
||||
[grams, item.weights[grams]],
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/// The place [payload] holds, opened; null for one of a newer schema or
|
||||
/// one it can't read. An item of a kind it doesn't know is left out, as is
|
||||
/// a weight that isn't one.
|
||||
PlaceContent? decodePlace(ByteData payload) {
|
||||
try {
|
||||
final json = jsonDecode(
|
||||
utf8.decode(Uint8List.sublistView(payload)),
|
||||
) as Map<String, Object?>;
|
||||
final version = json['schemaVersion']! as int;
|
||||
if (version > placeSchemaVersion) {
|
||||
log('A place of schema $version skipped', name: 'Place');
|
||||
return null;
|
||||
}
|
||||
return PlaceContent(
|
||||
name: json['name']! as String,
|
||||
items: [
|
||||
for (final item in json['items']! as List<Object?>)
|
||||
if (item case final Map<String, Object?> fields
|
||||
when EquipmentKind.values.asNameMap()[fields['kind']] != null)
|
||||
EquipmentItem(
|
||||
kind: EquipmentKind.values.byName(fields['kind']! as String),
|
||||
name: fields['name'] as String?,
|
||||
count: switch (fields['count']) {
|
||||
final int count when count > 0 => count,
|
||||
_ => 1,
|
||||
},
|
||||
grams: switch (fields['grams']) {
|
||||
final int grams when grams > 0 => grams,
|
||||
_ => null,
|
||||
},
|
||||
weights: {
|
||||
for (final pair in fields['weights'] as List<Object?>? ?? [])
|
||||
if (pair case [final int grams, final int count]
|
||||
when grams > 0 && count > 0)
|
||||
grams: count,
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
} on Object catch (error) {
|
||||
log('A place not read: ${error.runtimeType}', name: 'Place');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:halkyon_app/halkyon_app.dart';
|
||||
import 'package:halkyon_train_client/halkyon_train_client.dart' show Uuid;
|
||||
import 'package:halkyon_train_flutter/src/core/privacy/train_keys.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/place_gateway.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/data/place_payload.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/equipment/model/equipment.dart';
|
||||
|
||||
/// The places the person trains at (ADR 0034), sealed with their key for
|
||||
/// their row as workouts are (D7); a readable row is one the instance made
|
||||
/// up, and shows locked.
|
||||
class PlaceRepository(final PlaceGateway _gateway, final TrainKeys _keys) {
|
||||
StreamSubscription<void>? _remote;
|
||||
|
||||
/// This device's changes, and those a sync brings while anyone listens.
|
||||
late final StreamController<void> _changes = StreamController.broadcast(
|
||||
onListen: () => _remote = _gateway.remoteChanges.listen(_changes.add),
|
||||
onCancel: () => _remote?.cancel(),
|
||||
);
|
||||
|
||||
late final _envelope = PayloadEnvelope(_keys.cipher);
|
||||
|
||||
/// Fires when the places changed, here or on the person's other devices.
|
||||
Stream<void> get changes => _changes.stream;
|
||||
|
||||
/// Every place, in the order they were made; one that doesn't open here
|
||||
/// with its content null.
|
||||
Future<List<StoredPlace>> all() async {
|
||||
await _keys.refresh();
|
||||
final rows = await _gateway.places()
|
||||
..sort((a, b) => a.id.compareTo(b.id));
|
||||
return [
|
||||
for (final row in rows)
|
||||
StoredPlace(row.id, switch (_open(row.envelope, row.id)) {
|
||||
final payload? => decodePlace(payload),
|
||||
null => null,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/// Keeps a new place and returns its id; throws [KeysMissing] where this
|
||||
/// device can't seal.
|
||||
Future<String> save(PlaceContent content) async {
|
||||
final id = const Uuid().v7();
|
||||
await _gateway.insert((id: id, envelope: await _sealed(id, content)));
|
||||
_changes.add(null);
|
||||
return id;
|
||||
}
|
||||
|
||||
Future<void> update(String id, PlaceContent content) async {
|
||||
await _gateway.update(id, await _sealed(id, content));
|
||||
_changes.add(null);
|
||||
}
|
||||
|
||||
Future<void> delete(String id) async {
|
||||
await _gateway.delete(id);
|
||||
_changes.add(null);
|
||||
}
|
||||
|
||||
/// Closes what it holds open.
|
||||
Future<void> dispose() => _changes.close();
|
||||
|
||||
Future<Envelope> _sealed(String id, PlaceContent content) async =>
|
||||
_envelope.seal(
|
||||
encodePlace(content),
|
||||
keyId: await _keys.keyToWrite(),
|
||||
table: 'training_place',
|
||||
id: id,
|
||||
);
|
||||
|
||||
ByteData? _open(Envelope envelope, String id) {
|
||||
if (envelope.keyId == null) {
|
||||
return null;
|
||||
}
|
||||
return switch (_envelope.open(envelope, table: 'training_place', id: id)) {
|
||||
Readable(:final payload) => payload,
|
||||
Locked() => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue