From f32cd74232a62b63fbbade4231c892b78e8bca46 Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:01:04 +0530 Subject: [PATCH] feat: show stacks in asset viewer (#19935) * feat: show stacks in asset viewer * fix: global key issue and flash on stack asset change * feat(mobile): stack and unstack action (#19941) * feat(mobile): stack and unstack action * add custom model * use stackId from ActionSource * Update mobile/lib/providers/infrastructure/action.provider.dart Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> --------- Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> * fix: lint * fix: bad merge * fix: test --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex Co-authored-by: Daimolean <92239625+wuzihao051119@users.noreply.github.com> Co-authored-by: wuzihao051119 --- i18n/en.json | 2 + .../drift_schemas/main/drift_schema_v1.json | 2 +- .../drift_schemas/main/drift_schema_v2.json | 2 +- .../lib/immich_mobile_immich_lint.dart | 2 +- .../models/asset/local_asset.model.dart | 1 + .../models/asset/remote_asset.model.dart | 21 +- mobile/lib/domain/models/stack.model.dart | 24 + mobile/lib/domain/models/timeline.model.dart | 6 + mobile/lib/domain/services/asset.service.dart | 11 + mobile/lib/domain/utils/event_stream.dart | 10 +- .../entities/merged_asset.drift | 39 +- .../entities/merged_asset.drift.dart | 17 +- .../entities/remote_asset.entity.dart | 3 + .../entities/remote_asset.entity.drift.dart | 68 +- .../repositories/db.repository.drift.dart | 138 ++-- .../repositories/db.repository.steps.dart | 280 +++++---- .../repositories/remote_asset.repository.dart | 100 ++- .../repositories/sync_stream.repository.dart | 1 + .../repositories/timeline.repository.dart | 2 + .../pages/dev/main_timeline.page.dart | 5 +- .../stack_action_button.widget.dart | 42 +- .../unstack_action_button.widget.dart | 49 ++ .../asset_viewer/asset_stack.provider.dart | 24 + .../asset_viewer/asset_stack.widget.dart | 119 ++++ .../asset_viewer/asset_viewer.page.dart | 37 +- .../asset_viewer/asset_viewer.state.dart | 30 +- .../archive_bottom_sheet.widget.dart | 2 +- .../favorite_bottom_sheet.widget.dart | 2 +- .../general_bottom_sheet.widget.dart | 2 +- .../remote_album_bottom_sheet.widget.dart | 2 +- .../widgets/images/thumbnail_tile.widget.dart | 54 +- .../widgets/timeline/timeline.state.dart | 4 + .../widgets/timeline/timeline.widget.dart | 3 + .../infrastructure/action.provider.dart | 72 ++- .../repositories/asset_api.repository.dart | 26 +- mobile/lib/services/action.service.dart | 10 + .../common/mesmerizing_sliver_app_bar.dart | 1 + .../common/remote_album_sliver_app_bar.dart | 1 + mobile/lib/widgets/map/map_thumbnail.dart | 10 +- .../test/drift/main/generated/schema_v1.dart | 590 ++++++++++-------- .../test/drift/main/generated/schema_v2.dart | 556 +++++++++-------- 41 files changed, 1568 insertions(+), 802 deletions(-) create mode 100644 mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart create mode 100644 mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart create mode 100644 mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart diff --git a/i18n/en.json b/i18n/en.json index 89780f62b1..dfe2954c9f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1795,6 +1795,7 @@ "sort_title": "Title", "source": "Source", "stack": "Stack", + "stack_action_prompt": "{count} stacked", "stack_duplicates": "Stack duplicates", "stack_select_one_photo": "Select one main photo for the stack", "stack_selected_photos": "Stack selected photos", @@ -1905,6 +1906,7 @@ "unselect_all_duplicates": "Unselect all duplicates", "unselect_all_in": "Unselect all in {group}", "unstack": "Un-stack", + "unstack_action_prompt": "{count} unstacked", "unstacked_assets_count": "Un-stacked {count, plural, one {# asset} other {# assets}}", "untagged": "Untagged", "up_next": "Up next", diff --git a/mobile/drift_schemas/main/drift_schema_v1.json b/mobile/drift_schemas/main/drift_schema_v1.json index 03656ce0b4..c19bcfb945 100644 --- a/mobile/drift_schemas/main/drift_schema_v1.json +++ b/mobile/drift_schemas/main/drift_schema_v1.json @@ -1 +1 @@ -{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[2],"type":"index","data":{"on":2,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":4,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":5,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":6,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":7,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":8,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":9,"references":[2,8],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":10,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":11,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":12,"references":[1,11],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":13,"references":[11,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":14,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":15,"references":[1,14],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":16,"references":[0,1],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[0,1],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[2],"type":"index","data":{"on":2,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":5,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":6,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":8,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":9,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":10,"references":[2,9],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":11,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":12,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":13,"references":[1,12],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":14,"references":[12,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":15,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":16,"references":[1,15],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}}]} \ No newline at end of file diff --git a/mobile/drift_schemas/main/drift_schema_v2.json b/mobile/drift_schemas/main/drift_schema_v2.json index 4c1e3d68a1..c19bcfb945 100644 --- a/mobile/drift_schemas/main/drift_schema_v2.json +++ b/mobile/drift_schemas/main/drift_schema_v2.json @@ -1 +1 @@ -{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[2],"type":"index","data":{"on":2,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":4,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":5,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":6,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":7,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":8,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":9,"references":[2,8],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":10,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":11,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":12,"references":[1,11],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":13,"references":[11,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":14,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":15,"references":[1,14],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}},{"id":16,"references":[0,1],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}}]} \ No newline at end of file +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":true},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"user_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_admin","getter_name":"isAdmin","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_admin\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_admin\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"email","getter_name":"email","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"profile_image_path","getter_name":"profileImagePath","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"quota_size_in_bytes","getter_name":"quotaSizeInBytes","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"quota_usage_in_bytes","getter_name":"quotaUsageInBytes","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":1,"references":[0],"type":"table","data":{"name":"remote_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"local_date_time","getter_name":"localDateTime","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"thumb_hash","getter_name":"thumbHash","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"live_photo_video_id","getter_name":"livePhotoVideoId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"visibility","getter_name":"visibility","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetVisibility.values)","dart_type_name":"AssetVisibility"}},{"name":"stack_id","getter_name":"stackId","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":2,"references":[],"type":"table","data":{"name":"local_asset_entity","was_declared_in_moor":false,"columns":[{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AssetType.values)","dart_type_name":"AssetType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"duration_in_seconds","getter_name":"durationInSeconds","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"checksum","getter_name":"checksum","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_favorite","getter_name":"isFavorite","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_favorite\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_favorite\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":3,"references":[0,1],"type":"table","data":{"name":"stack_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"primary_asset_id","getter_name":"primaryAssetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":4,"references":[2],"type":"index","data":{"on":2,"name":"idx_local_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":5,"references":[1],"type":"index","data":{"on":1,"name":"UQ_remote_asset_owner_checksum","sql":null,"unique":true,"columns":["checksum","owner_id"]}},{"id":6,"references":[1],"type":"index","data":{"on":1,"name":"idx_remote_asset_checksum","sql":null,"unique":false,"columns":["checksum"]}},{"id":7,"references":[0],"type":"table","data":{"name":"user_metadata_entity","was_declared_in_moor":false,"columns":[{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"key","getter_name":"key","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(UserMetadataKey.values)","dart_type_name":"UserMetadataKey"}},{"name":"value","getter_name":"value","moor_type":"blob","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"userMetadataConverter","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["user_id","key"]}},{"id":8,"references":[0],"type":"table","data":{"name":"partner_entity","was_declared_in_moor":false,"columns":[{"name":"shared_by_id","getter_name":"sharedById","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"shared_with_id","getter_name":"sharedWithId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"in_timeline","getter_name":"inTimeline","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"in_timeline\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"in_timeline\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["shared_by_id","shared_with_id"]}},{"id":9,"references":[],"type":"table","data":{"name":"local_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"backup_selection","getter_name":"backupSelection","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(BackupSelection.values)","dart_type_name":"BackupSelection"}},{"name":"is_ios_shared_album","getter_name":"isIosSharedAlbum","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_ios_shared_album\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_ios_shared_album\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"marker","getter_name":"marker_","moor_type":"bool","nullable":true,"customConstraints":null,"defaultConstraints":"CHECK (\"marker\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"marker\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":10,"references":[2,9],"type":"table","data":{"name":"local_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES local_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES local_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":11,"references":[1],"type":"table","data":{"name":"remote_exif_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"city","getter_name":"city","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"state","getter_name":"state","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"country","getter_name":"country","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"date_time_original","getter_name":"dateTimeOriginal","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"height","getter_name":"height","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"width","getter_name":"width","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"exposure_time","getter_name":"exposureTime","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"f_number","getter_name":"fNumber","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"file_size","getter_name":"fileSize","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"focal_length","getter_name":"focalLength","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"latitude","getter_name":"latitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"longitude","getter_name":"longitude","moor_type":"double","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"iso","getter_name":"iso","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"make","getter_name":"make","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"model","getter_name":"model","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"lens","getter_name":"lens","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"orientation","getter_name":"orientation","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"time_zone","getter_name":"timeZone","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"rating","getter_name":"rating","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"projection_type","getter_name":"projectionType","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id"]}},{"id":12,"references":[0,1],"type":"table","data":{"name":"remote_album_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"description","getter_name":"description","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('\\'\\'')","default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"thumbnail_asset_id","getter_name":"thumbnailAssetId","moor_type":"string","nullable":true,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE SET NULL"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"is_activity_enabled","getter_name":"isActivityEnabled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_activity_enabled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_activity_enabled\" IN (0, 1))"},"default_dart":"const CustomExpression('1')","default_client_dart":null,"dsl_features":[]},{"name":"order","getter_name":"order","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumAssetOrder.values)","dart_type_name":"AlbumAssetOrder"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":13,"references":[1,12],"type":"table","data":{"name":"remote_album_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","album_id"]}},{"id":14,"references":[12,0],"type":"table","data":{"name":"remote_album_user_entity","was_declared_in_moor":false,"columns":[{"name":"album_id","getter_name":"albumId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_album_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_album_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"user_id","getter_name":"userId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"role","getter_name":"role","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(AlbumUserRole.values)","dart_type_name":"AlbumUserRole"}}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["album_id","user_id"]}},{"id":15,"references":[0],"type":"table","data":{"name":"memory_entity","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"updated_at","getter_name":"updatedAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CURRENT_TIMESTAMP')","default_client_dart":null,"dsl_features":[]},{"name":"deleted_at","getter_name":"deletedAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"owner_id","getter_name":"ownerId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES user_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES user_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"type","getter_name":"type","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumIndexConverter(MemoryTypeEnum.values)","dart_type_name":"MemoryTypeEnum"}},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_saved","getter_name":"isSaved","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_saved\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_saved\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]},{"name":"memory_at","getter_name":"memoryAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"seen_at","getter_name":"seenAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"show_at","getter_name":"showAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"hide_at","getter_name":"hideAt","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["id"]}},{"id":16,"references":[1,15],"type":"table","data":{"name":"memory_asset_entity","was_declared_in_moor":false,"columns":[{"name":"asset_id","getter_name":"assetId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES remote_asset_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"memory_id","getter_name":"memoryId","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES memory_entity (id) ON DELETE CASCADE","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES memory_entity (id) ON DELETE CASCADE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]}],"is_virtual":false,"without_rowid":true,"constraints":[],"strict":true,"explicit_pk":["asset_id","memory_id"]}}]} \ No newline at end of file diff --git a/mobile/immich_lint/lib/immich_mobile_immich_lint.dart b/mobile/immich_lint/lib/immich_mobile_immich_lint.dart index e2622fadd1..7d3ed4757e 100644 --- a/mobile/immich_lint/lib/immich_mobile_immich_lint.dart +++ b/mobile/immich_lint/lib/immich_mobile_immich_lint.dart @@ -23,7 +23,7 @@ class ImmichLinter extends PluginBase { return rules; } - static makeCode(String name, LintOptions options) => LintCode( + static LintCode makeCode(String name, LintOptions options) => LintCode( name: name, problemMessage: options.json["message"] as String, errorSeverity: ErrorSeverity.WARNING, diff --git a/mobile/lib/domain/models/asset/local_asset.model.dart b/mobile/lib/domain/models/asset/local_asset.model.dart index 0c3e8fa942..3466a0f25b 100644 --- a/mobile/lib/domain/models/asset/local_asset.model.dart +++ b/mobile/lib/domain/models/asset/local_asset.model.dart @@ -45,6 +45,7 @@ class LocalAsset extends BaseAsset { }'''; } + // Not checking for remoteId here @override bool operator ==(Object other) { if (other is! LocalAsset) return false; diff --git a/mobile/lib/domain/models/asset/remote_asset.model.dart b/mobile/lib/domain/models/asset/remote_asset.model.dart index 9e4cfa1f19..760a16170b 100644 --- a/mobile/lib/domain/models/asset/remote_asset.model.dart +++ b/mobile/lib/domain/models/asset/remote_asset.model.dart @@ -14,6 +14,8 @@ class RemoteAsset extends BaseAsset { final String? thumbHash; final AssetVisibility visibility; final String ownerId; + final String? stackId; + final int stackCount; const RemoteAsset({ required this.id, @@ -31,6 +33,8 @@ class RemoteAsset extends BaseAsset { this.thumbHash, this.visibility = AssetVisibility.timeline, super.livePhotoVideoId, + this.stackId, + this.stackCount = 0, }); @override @@ -56,9 +60,14 @@ class RemoteAsset extends BaseAsset { isFavorite: $isFavorite, thumbHash: ${thumbHash ?? ""}, visibility: $visibility, + stackId: ${stackId ?? ""}, + stackCount: $stackCount, + checksum: $checksum, + livePhotoVideoId: ${livePhotoVideoId ?? ""}, }'''; } + // Not checking for localId here @override bool operator ==(Object other) { if (other is! RemoteAsset) return false; @@ -67,7 +76,9 @@ class RemoteAsset extends BaseAsset { id == other.id && ownerId == other.ownerId && thumbHash == other.thumbHash && - visibility == other.visibility; + visibility == other.visibility && + stackId == other.stackId && + stackCount == other.stackCount; } @override @@ -77,7 +88,9 @@ class RemoteAsset extends BaseAsset { ownerId.hashCode ^ localId.hashCode ^ thumbHash.hashCode ^ - visibility.hashCode; + visibility.hashCode ^ + stackId.hashCode ^ + stackCount.hashCode; RemoteAsset copyWith({ String? id, @@ -95,6 +108,8 @@ class RemoteAsset extends BaseAsset { String? thumbHash, AssetVisibility? visibility, String? livePhotoVideoId, + String? stackId, + int? stackCount, }) { return RemoteAsset( id: id ?? this.id, @@ -112,6 +127,8 @@ class RemoteAsset extends BaseAsset { thumbHash: thumbHash ?? this.thumbHash, visibility: visibility ?? this.visibility, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, + stackId: stackId ?? this.stackId, + stackCount: stackCount ?? this.stackCount, ); } } diff --git a/mobile/lib/domain/models/stack.model.dart b/mobile/lib/domain/models/stack.model.dart index 5404eb8f42..d7faf07a22 100644 --- a/mobile/lib/domain/models/stack.model.dart +++ b/mobile/lib/domain/models/stack.model.dart @@ -82,3 +82,27 @@ class Stack { primaryAssetId.hashCode; } } + +class StackResponse { + final String id; + final String primaryAssetId; + final List assetIds; + + const StackResponse({ + required this.id, + required this.primaryAssetId, + required this.assetIds, + }); + + @override + bool operator ==(covariant StackResponse other) { + if (identical(this, other)) return true; + + return other.id == id && + other.primaryAssetId == primaryAssetId && + other.assetIds == assetIds; + } + + @override + int get hashCode => id.hashCode ^ primaryAssetId.hashCode ^ assetIds.hashCode; +} diff --git a/mobile/lib/domain/models/timeline.model.dart b/mobile/lib/domain/models/timeline.model.dart index 4a49708b74..f3b688b8b8 100644 --- a/mobile/lib/domain/models/timeline.model.dart +++ b/mobile/lib/domain/models/timeline.model.dart @@ -1,3 +1,5 @@ +import 'package:immich_mobile/domain/utils/event_stream.dart'; + enum GroupAssetsBy { day, month, @@ -38,3 +40,7 @@ class TimeBucket extends Bucket { @override int get hashCode => super.hashCode ^ date.hashCode; } + +class TimelineReloadEvent extends Event { + const TimelineReloadEvent(); +} diff --git a/mobile/lib/domain/services/asset.service.dart b/mobile/lib/domain/services/asset.service.dart index 2c9b493187..63b1aad8c1 100644 --- a/mobile/lib/domain/services/asset.service.dart +++ b/mobile/lib/domain/services/asset.service.dart @@ -24,6 +24,17 @@ class AssetService { : _remoteAssetRepository.watchAsset(id); } + Future> getStack(RemoteAsset asset) async { + if (asset.stackId == null) { + return []; + } + + return _remoteAssetRepository.getStackChildren(asset).then((assets) { + // Include the primary asset in the stack as the first item + return [asset, ...assets]; + }); + } + Future getExif(BaseAsset asset) async { if (!asset.hasRemote) { return null; diff --git a/mobile/lib/domain/utils/event_stream.dart b/mobile/lib/domain/utils/event_stream.dart index 65ee17e12b..e728ece58b 100644 --- a/mobile/lib/domain/utils/event_stream.dart +++ b/mobile/lib/domain/utils/event_stream.dart @@ -1,17 +1,9 @@ import 'dart:async'; -sealed class Event { +class Event { const Event(); } -class TimelineReloadEvent extends Event { - const TimelineReloadEvent(); -} - -class ViewerOpenBottomSheetEvent extends Event { - const ViewerOpenBottomSheetEvent(); -} - class EventStream { EventStream._(); diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift b/mobile/lib/infrastructure/entities/merged_asset.drift index e07edbc0c8..3dc7221c15 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift +++ b/mobile/lib/infrastructure/entities/merged_asset.drift @@ -1,5 +1,6 @@ import 'remote_asset.entity.dart'; import 'local_asset.entity.dart'; +import 'stack.entity.dart'; mergedAsset: SELECT * FROM ( @@ -18,13 +19,33 @@ mergedAsset: SELECT * FROM rae.checksum, rae.owner_id, rae.live_photo_video_id, - 0 as orientation + 0 as orientation, + rae.stack_id, + COALESCE(stack_count.total_count, 0) AS stack_count FROM remote_asset_entity rae LEFT JOIN local_asset_entity lae ON rae.checksum = lae.checksum + LEFT JOIN + stack_entity se ON rae.stack_id = se.id + LEFT JOIN + (SELECT + stack_id, + COUNT(*) AS total_count + FROM remote_asset_entity + WHERE deleted_at IS NULL + AND visibility = 0 + AND stack_id IS NOT NULL + GROUP BY stack_id + ) AS stack_count ON rae.stack_id = stack_count.stack_id WHERE - rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ? + rae.deleted_at IS NULL + AND rae.visibility = 0 + AND rae.owner_id in ? + AND ( + rae.stack_id IS NULL + OR rae.id = se.primary_asset_id + ) UNION ALL SELECT NULL as remote_id, @@ -41,7 +62,9 @@ mergedAsset: SELECT * FROM lae.checksum, NULL as owner_id, NULL as live_photo_video_id, - lae.orientation + lae.orientation, + NULL as stack_id, + 0 AS stack_count FROM local_asset_entity lae LEFT JOIN @@ -68,8 +91,16 @@ FROM remote_asset_entity rae LEFT JOIN local_asset_entity lae ON rae.checksum = lae.checksum + LEFT JOIN + stack_entity se ON rae.stack_id = se.id WHERE - rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id in ? + rae.deleted_at IS NULL + AND rae.visibility = 0 + AND rae.owner_id in ? + AND ( + rae.stack_id IS NULL + OR rae.id = se.primary_asset_id + ) UNION ALL SELECT lae.name, diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift.dart b/mobile/lib/infrastructure/entities/merged_asset.drift.dart index 4ee0643706..ac3db868e1 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift.dart +++ b/mobile/lib/infrastructure/entities/merged_asset.drift.dart @@ -7,6 +7,8 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift. as i3; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' as i4; +import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' + as i5; class MergedAssetDrift extends i1.ModularAccessor { MergedAssetDrift(i0.GeneratedDatabase db) : super(db); @@ -18,7 +20,7 @@ class MergedAssetDrift extends i1.ModularAccessor { final generatedlimit = $write(limit, startIndex: $arrayStartIndex); $arrayStartIndex += generatedlimit.amountOfVariables; return customSelect( - 'SELECT * FROM (SELECT rae.id AS remote_id, lae.id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}', + 'SELECT * FROM (SELECT rae.id AS remote_id, lae.id AS local_id, rae.name, rae.type, rae.created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, COALESCE(stack_count.total_count, 0) AS stack_count FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id LEFT JOIN (SELECT stack_id, COUNT(*) AS total_count FROM remote_asset_entity WHERE deleted_at IS NULL AND visibility = 0 AND stack_id IS NOT NULL GROUP BY stack_id) AS stack_count ON rae.stack_id = stack_count.stack_id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar1) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, 0 AS stack_count FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) ORDER BY created_at DESC ${generatedlimit.sql}', variables: [ for (var $ in var1) i0.Variable($), ...generatedlimit.introducedVariables @@ -26,6 +28,7 @@ class MergedAssetDrift extends i1.ModularAccessor { readsFrom: { remoteAssetEntity, localAssetEntity, + stackEntity, ...generatedlimit.watchedTables, }).map((i0.QueryRow row) => MergedAssetResult( remoteId: row.readNullable('remote_id'), @@ -44,6 +47,8 @@ class MergedAssetDrift extends i1.ModularAccessor { ownerId: row.readNullable('owner_id'), livePhotoVideoId: row.readNullable('live_photo_video_id'), orientation: row.read('orientation'), + stackId: row.readNullable('stack_id'), + stackCount: row.read('stack_count'), )); } @@ -53,7 +58,7 @@ class MergedAssetDrift extends i1.ModularAccessor { final expandedvar2 = $expandVar($arrayStartIndex, var2.length); $arrayStartIndex += var2.length; return customSelect( - 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC', + 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.name, rae.created_at FROM remote_asset_entity AS rae LEFT JOIN local_asset_entity AS lae ON rae.checksum = lae.checksum LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandedvar2) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.name, lae.created_at FROM local_asset_entity AS lae LEFT JOIN remote_asset_entity AS rae ON rae.checksum = lae.checksum WHERE rae.id IS NULL) GROUP BY bucket_date ORDER BY bucket_date DESC', variables: [ i0.Variable(groupBy), for (var $ in var2) i0.Variable($) @@ -61,6 +66,7 @@ class MergedAssetDrift extends i1.ModularAccessor { readsFrom: { remoteAssetEntity, localAssetEntity, + stackEntity, }).map((i0.QueryRow row) => MergedBucketResult( assetCount: row.read('asset_count'), bucketDate: row.read('bucket_date'), @@ -73,6 +79,9 @@ class MergedAssetDrift extends i1.ModularAccessor { i4.$LocalAssetEntityTable get localAssetEntity => i1.ReadDatabaseContainer(attachedDatabase) .resultSet('local_asset_entity'); + i5.$StackEntityTable get stackEntity => + i1.ReadDatabaseContainer(attachedDatabase) + .resultSet('stack_entity'); } class MergedAssetResult { @@ -91,6 +100,8 @@ class MergedAssetResult { final String? ownerId; final String? livePhotoVideoId; final int orientation; + final String? stackId; + final int stackCount; MergedAssetResult({ this.remoteId, this.localId, @@ -107,6 +118,8 @@ class MergedAssetResult { this.ownerId, this.livePhotoVideoId, required this.orientation, + this.stackId, + required this.stackCount, }); } diff --git a/mobile/lib/infrastructure/entities/remote_asset.entity.dart b/mobile/lib/infrastructure/entities/remote_asset.entity.dart index 96193e0415..0b2896538e 100644 --- a/mobile/lib/infrastructure/entities/remote_asset.entity.dart +++ b/mobile/lib/infrastructure/entities/remote_asset.entity.dart @@ -34,6 +34,8 @@ class RemoteAssetEntity extends Table IntColumn get visibility => intEnum()(); + TextColumn get stackId => text().nullable()(); + @override Set get primaryKey => {id}; } @@ -55,5 +57,6 @@ extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData { visibility: visibility, livePhotoVideoId: livePhotoVideoId, localId: null, + stackId: stackId, ); } diff --git a/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart index 2bb7cffe59..543ed65985 100644 --- a/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart +++ b/mobile/lib/infrastructure/entities/remote_asset.entity.drift.dart @@ -29,6 +29,7 @@ typedef $$RemoteAssetEntityTableCreateCompanionBuilder i0.Value deletedAt, i0.Value livePhotoVideoId, required i2.AssetVisibility visibility, + i0.Value stackId, }); typedef $$RemoteAssetEntityTableUpdateCompanionBuilder = i1.RemoteAssetEntityCompanion Function({ @@ -48,6 +49,7 @@ typedef $$RemoteAssetEntityTableUpdateCompanionBuilder i0.Value deletedAt, i0.Value livePhotoVideoId, i0.Value visibility, + i0.Value stackId, }); final class $$RemoteAssetEntityTableReferences extends i0.BaseReferences< @@ -145,6 +147,9 @@ class $$RemoteAssetEntityTableFilterComposer column: $table.visibility, builder: (column) => i0.ColumnWithTypeConverterFilters(column)); + i0.ColumnFilters get stackId => $composableBuilder( + column: $table.stackId, builder: (column) => i0.ColumnFilters(column)); + i5.$$UserEntityTableFilterComposer get ownerId { final i5.$$UserEntityTableFilterComposer composer = $composerBuilder( composer: this, @@ -231,6 +236,9 @@ class $$RemoteAssetEntityTableOrderingComposer column: $table.visibility, builder: (column) => i0.ColumnOrderings(column)); + i0.ColumnOrderings get stackId => $composableBuilder( + column: $table.stackId, builder: (column) => i0.ColumnOrderings(column)); + i5.$$UserEntityTableOrderingComposer get ownerId { final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder( composer: this, @@ -309,6 +317,9 @@ class $$RemoteAssetEntityTableAnnotationComposer $composableBuilder( column: $table.visibility, builder: (column) => column); + i0.GeneratedColumn get stackId => + $composableBuilder(column: $table.stackId, builder: (column) => column); + i5.$$UserEntityTableAnnotationComposer get ownerId { final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder( composer: this, @@ -373,6 +384,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< i0.Value deletedAt = const i0.Value.absent(), i0.Value livePhotoVideoId = const i0.Value.absent(), i0.Value visibility = const i0.Value.absent(), + i0.Value stackId = const i0.Value.absent(), }) => i1.RemoteAssetEntityCompanion( name: name, @@ -391,6 +403,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< deletedAt: deletedAt, livePhotoVideoId: livePhotoVideoId, visibility: visibility, + stackId: stackId, ), createCompanionCallback: ({ required String name, @@ -409,6 +422,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< i0.Value deletedAt = const i0.Value.absent(), i0.Value livePhotoVideoId = const i0.Value.absent(), required i2.AssetVisibility visibility, + i0.Value stackId = const i0.Value.absent(), }) => i1.RemoteAssetEntityCompanion.insert( name: name, @@ -427,6 +441,7 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager< deletedAt: deletedAt, livePhotoVideoId: livePhotoVideoId, visibility: visibility, + stackId: stackId, ), withReferenceMapper: (p0) => p0 .map((e) => ( @@ -602,6 +617,12 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity type: i0.DriftSqlType.int, requiredDuringInsert: true) .withConverter( i1.$RemoteAssetEntityTable.$convertervisibility); + static const i0.VerificationMeta _stackIdMeta = + const i0.VerificationMeta('stackId'); + @override + late final i0.GeneratedColumn stackId = i0.GeneratedColumn( + 'stack_id', aliasedName, true, + type: i0.DriftSqlType.string, requiredDuringInsert: false); @override List get $columns => [ name, @@ -619,7 +640,8 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity thumbHash, deletedAt, livePhotoVideoId, - visibility + visibility, + stackId ]; @override String get aliasedName => _alias ?? actualTableName; @@ -703,6 +725,10 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity livePhotoVideoId.isAcceptableOrUnknown( data['live_photo_video_id']!, _livePhotoVideoIdMeta)); } + if (data.containsKey('stack_id')) { + context.handle(_stackIdMeta, + stackId.isAcceptableOrUnknown(data['stack_id']!, _stackIdMeta)); + } return context; } @@ -748,6 +774,8 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity visibility: i1.$RemoteAssetEntityTable.$convertervisibility.fromSql( attachedDatabase.typeMapping.read( i0.DriftSqlType.int, data['${effectivePrefix}visibility'])!), + stackId: attachedDatabase.typeMapping + .read(i0.DriftSqlType.string, data['${effectivePrefix}stack_id']), ); } @@ -785,6 +813,7 @@ class RemoteAssetEntityData extends i0.DataClass final DateTime? deletedAt; final String? livePhotoVideoId; final i2.AssetVisibility visibility; + final String? stackId; const RemoteAssetEntityData( {required this.name, required this.type, @@ -801,7 +830,8 @@ class RemoteAssetEntityData extends i0.DataClass this.thumbHash, this.deletedAt, this.livePhotoVideoId, - required this.visibility}); + required this.visibility, + this.stackId}); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -841,6 +871,9 @@ class RemoteAssetEntityData extends i0.DataClass map['visibility'] = i0.Variable( i1.$RemoteAssetEntityTable.$convertervisibility.toSql(visibility)); } + if (!nullToAbsent || stackId != null) { + map['stack_id'] = i0.Variable(stackId); + } return map; } @@ -866,6 +899,7 @@ class RemoteAssetEntityData extends i0.DataClass livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), visibility: i1.$RemoteAssetEntityTable.$convertervisibility .fromJson(serializer.fromJson(json['visibility'])), + stackId: serializer.fromJson(json['stackId']), ); } @override @@ -890,6 +924,7 @@ class RemoteAssetEntityData extends i0.DataClass 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), 'visibility': serializer.toJson( i1.$RemoteAssetEntityTable.$convertervisibility.toJson(visibility)), + 'stackId': serializer.toJson(stackId), }; } @@ -909,7 +944,8 @@ class RemoteAssetEntityData extends i0.DataClass i0.Value thumbHash = const i0.Value.absent(), i0.Value deletedAt = const i0.Value.absent(), i0.Value livePhotoVideoId = const i0.Value.absent(), - i2.AssetVisibility? visibility}) => + i2.AssetVisibility? visibility, + i0.Value stackId = const i0.Value.absent()}) => i1.RemoteAssetEntityData( name: name ?? this.name, type: type ?? this.type, @@ -932,6 +968,7 @@ class RemoteAssetEntityData extends i0.DataClass ? livePhotoVideoId.value : this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, ); RemoteAssetEntityData copyWithCompanion(i1.RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( @@ -959,6 +996,7 @@ class RemoteAssetEntityData extends i0.DataClass : this.livePhotoVideoId, visibility: data.visibility.present ? data.visibility.value : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -980,7 +1018,8 @@ class RemoteAssetEntityData extends i0.DataClass ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') - ..write('visibility: $visibility') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } @@ -1002,7 +1041,8 @@ class RemoteAssetEntityData extends i0.DataClass thumbHash, deletedAt, livePhotoVideoId, - visibility); + visibility, + stackId); @override bool operator ==(Object other) => identical(this, other) || @@ -1022,7 +1062,8 @@ class RemoteAssetEntityData extends i0.DataClass other.thumbHash == this.thumbHash && other.deletedAt == this.deletedAt && other.livePhotoVideoId == this.livePhotoVideoId && - other.visibility == this.visibility); + other.visibility == this.visibility && + other.stackId == this.stackId); } class RemoteAssetEntityCompanion @@ -1043,6 +1084,7 @@ class RemoteAssetEntityCompanion final i0.Value deletedAt; final i0.Value livePhotoVideoId; final i0.Value visibility; + final i0.Value stackId; const RemoteAssetEntityCompanion({ this.name = const i0.Value.absent(), this.type = const i0.Value.absent(), @@ -1060,6 +1102,7 @@ class RemoteAssetEntityCompanion this.deletedAt = const i0.Value.absent(), this.livePhotoVideoId = const i0.Value.absent(), this.visibility = const i0.Value.absent(), + this.stackId = const i0.Value.absent(), }); RemoteAssetEntityCompanion.insert({ required String name, @@ -1078,6 +1121,7 @@ class RemoteAssetEntityCompanion this.deletedAt = const i0.Value.absent(), this.livePhotoVideoId = const i0.Value.absent(), required i2.AssetVisibility visibility, + this.stackId = const i0.Value.absent(), }) : name = i0.Value(name), type = i0.Value(type), id = i0.Value(id), @@ -1101,6 +1145,7 @@ class RemoteAssetEntityCompanion i0.Expression? deletedAt, i0.Expression? livePhotoVideoId, i0.Expression? visibility, + i0.Expression? stackId, }) { return i0.RawValuesInsertable({ if (name != null) 'name': name, @@ -1119,6 +1164,7 @@ class RemoteAssetEntityCompanion if (deletedAt != null) 'deleted_at': deletedAt, if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, }); } @@ -1138,7 +1184,8 @@ class RemoteAssetEntityCompanion i0.Value? thumbHash, i0.Value? deletedAt, i0.Value? livePhotoVideoId, - i0.Value? visibility}) { + i0.Value? visibility, + i0.Value? stackId}) { return i1.RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -1156,6 +1203,7 @@ class RemoteAssetEntityCompanion deletedAt: deletedAt ?? this.deletedAt, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, ); } @@ -1213,6 +1261,9 @@ class RemoteAssetEntityCompanion .$RemoteAssetEntityTable.$convertervisibility .toSql(visibility.value)); } + if (stackId.present) { + map['stack_id'] = i0.Variable(stackId.value); + } return map; } @@ -1234,7 +1285,8 @@ class RemoteAssetEntityCompanion ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') - ..write('visibility: $visibility') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } diff --git a/mobile/lib/infrastructure/repositories/db.repository.drift.dart b/mobile/lib/infrastructure/repositories/db.repository.drift.dart index 15d445d226..3b826c209b 100644 --- a/mobile/lib/infrastructure/repositories/db.repository.drift.dart +++ b/mobile/lib/infrastructure/repositories/db.repository.drift.dart @@ -7,27 +7,27 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift. as i2; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart' as i3; -import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart' - as i4; -import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart' - as i5; -import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' - as i6; -import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' - as i7; -import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart' - as i8; -import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart' - as i9; -import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart' - as i10; -import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart' - as i11; -import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart' - as i12; -import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart' - as i13; import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart' + as i4; +import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.drift.dart' + as i5; +import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart' + as i6; +import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart' + as i7; +import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.drift.dart' + as i8; +import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart' + as i9; +import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart' + as i10; +import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart' + as i11; +import 'package:immich_mobile/infrastructure/entities/remote_album_user.entity.drift.dart' + as i12; +import 'package:immich_mobile/infrastructure/entities/memory.entity.drift.dart' + as i13; +import 'package:immich_mobile/infrastructure/entities/memory_asset.entity.drift.dart' as i14; import 'package:immich_mobile/infrastructure/entities/merged_asset.drift.dart' as i15; @@ -41,26 +41,26 @@ abstract class $Drift extends i0.GeneratedDatabase { i2.$RemoteAssetEntityTable(this); late final i3.$LocalAssetEntityTable localAssetEntity = i3.$LocalAssetEntityTable(this); - late final i4.$UserMetadataEntityTable userMetadataEntity = - i4.$UserMetadataEntityTable(this); - late final i5.$PartnerEntityTable partnerEntity = - i5.$PartnerEntityTable(this); - late final i6.$LocalAlbumEntityTable localAlbumEntity = - i6.$LocalAlbumEntityTable(this); - late final i7.$LocalAlbumAssetEntityTable localAlbumAssetEntity = - i7.$LocalAlbumAssetEntityTable(this); - late final i8.$RemoteExifEntityTable remoteExifEntity = - i8.$RemoteExifEntityTable(this); - late final i9.$RemoteAlbumEntityTable remoteAlbumEntity = - i9.$RemoteAlbumEntityTable(this); - late final i10.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = - i10.$RemoteAlbumAssetEntityTable(this); - late final i11.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = - i11.$RemoteAlbumUserEntityTable(this); - late final i12.$MemoryEntityTable memoryEntity = i12.$MemoryEntityTable(this); - late final i13.$MemoryAssetEntityTable memoryAssetEntity = - i13.$MemoryAssetEntityTable(this); - late final i14.$StackEntityTable stackEntity = i14.$StackEntityTable(this); + late final i4.$StackEntityTable stackEntity = i4.$StackEntityTable(this); + late final i5.$UserMetadataEntityTable userMetadataEntity = + i5.$UserMetadataEntityTable(this); + late final i6.$PartnerEntityTable partnerEntity = + i6.$PartnerEntityTable(this); + late final i7.$LocalAlbumEntityTable localAlbumEntity = + i7.$LocalAlbumEntityTable(this); + late final i8.$LocalAlbumAssetEntityTable localAlbumAssetEntity = + i8.$LocalAlbumAssetEntityTable(this); + late final i9.$RemoteExifEntityTable remoteExifEntity = + i9.$RemoteExifEntityTable(this); + late final i10.$RemoteAlbumEntityTable remoteAlbumEntity = + i10.$RemoteAlbumEntityTable(this); + late final i11.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity = + i11.$RemoteAlbumAssetEntityTable(this); + late final i12.$RemoteAlbumUserEntityTable remoteAlbumUserEntity = + i12.$RemoteAlbumUserEntityTable(this); + late final i13.$MemoryEntityTable memoryEntity = i13.$MemoryEntityTable(this); + late final i14.$MemoryAssetEntityTable memoryAssetEntity = + i14.$MemoryAssetEntityTable(this); i15.MergedAssetDrift get mergedAssetDrift => i16.ReadDatabaseContainer(this) .accessor(i15.MergedAssetDrift.new); @override @@ -71,6 +71,7 @@ abstract class $Drift extends i0.GeneratedDatabase { userEntity, remoteAssetEntity, localAssetEntity, + stackEntity, i3.idxLocalAssetChecksum, i2.uQRemoteAssetOwnerChecksum, i2.idxRemoteAssetChecksum, @@ -83,8 +84,7 @@ abstract class $Drift extends i0.GeneratedDatabase { remoteAlbumAssetEntity, remoteAlbumUserEntity, memoryEntity, - memoryAssetEntity, - stackEntity + memoryAssetEntity ]; @override i0.StreamQueryUpdateRules get streamUpdateRules => @@ -97,6 +97,13 @@ abstract class $Drift extends i0.GeneratedDatabase { i0.TableUpdate('remote_asset_entity', kind: i0.UpdateKind.delete), ], ), + i0.WritePropagation( + on: i0.TableUpdateQuery.onTableName('user_entity', + limitUpdateKind: i0.UpdateKind.delete), + result: [ + i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete), + ], + ), i0.WritePropagation( on: i0.TableUpdateQuery.onTableName('user_entity', limitUpdateKind: i0.UpdateKind.delete), @@ -209,13 +216,6 @@ abstract class $Drift extends i0.GeneratedDatabase { i0.TableUpdate('memory_asset_entity', kind: i0.UpdateKind.delete), ], ), - i0.WritePropagation( - on: i0.TableUpdateQuery.onTableName('user_entity', - limitUpdateKind: i0.UpdateKind.delete), - result: [ - i0.TableUpdate('stack_entity', kind: i0.UpdateKind.delete), - ], - ), ], ); @override @@ -232,27 +232,27 @@ class $DriftManager { i2.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity); i3.$$LocalAssetEntityTableTableManager get localAssetEntity => i3.$$LocalAssetEntityTableTableManager(_db, _db.localAssetEntity); - i4.$$UserMetadataEntityTableTableManager get userMetadataEntity => - i4.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity); - i5.$$PartnerEntityTableTableManager get partnerEntity => - i5.$$PartnerEntityTableTableManager(_db, _db.partnerEntity); - i6.$$LocalAlbumEntityTableTableManager get localAlbumEntity => - i6.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity); - i7.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i7 + i4.$$StackEntityTableTableManager get stackEntity => + i4.$$StackEntityTableTableManager(_db, _db.stackEntity); + i5.$$UserMetadataEntityTableTableManager get userMetadataEntity => + i5.$$UserMetadataEntityTableTableManager(_db, _db.userMetadataEntity); + i6.$$PartnerEntityTableTableManager get partnerEntity => + i6.$$PartnerEntityTableTableManager(_db, _db.partnerEntity); + i7.$$LocalAlbumEntityTableTableManager get localAlbumEntity => + i7.$$LocalAlbumEntityTableTableManager(_db, _db.localAlbumEntity); + i8.$$LocalAlbumAssetEntityTableTableManager get localAlbumAssetEntity => i8 .$$LocalAlbumAssetEntityTableTableManager(_db, _db.localAlbumAssetEntity); - i8.$$RemoteExifEntityTableTableManager get remoteExifEntity => - i8.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity); - i9.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity => - i9.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity); - i10.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity => - i10.$$RemoteAlbumAssetEntityTableTableManager( + i9.$$RemoteExifEntityTableTableManager get remoteExifEntity => + i9.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity); + i10.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity => + i10.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity); + i11.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity => + i11.$$RemoteAlbumAssetEntityTableTableManager( _db, _db.remoteAlbumAssetEntity); - i11.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i11 + i12.$$RemoteAlbumUserEntityTableTableManager get remoteAlbumUserEntity => i12 .$$RemoteAlbumUserEntityTableTableManager(_db, _db.remoteAlbumUserEntity); - i12.$$MemoryEntityTableTableManager get memoryEntity => - i12.$$MemoryEntityTableTableManager(_db, _db.memoryEntity); - i13.$$MemoryAssetEntityTableTableManager get memoryAssetEntity => - i13.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity); - i14.$$StackEntityTableTableManager get stackEntity => - i14.$$StackEntityTableTableManager(_db, _db.stackEntity); + i13.$$MemoryEntityTableTableManager get memoryEntity => + i13.$$MemoryEntityTableTableManager(_db, _db.memoryEntity); + i14.$$MemoryAssetEntityTableTableManager get memoryAssetEntity => + i14.$$MemoryAssetEntityTableTableManager(_db, _db.memoryAssetEntity); } diff --git a/mobile/lib/infrastructure/repositories/db.repository.steps.dart b/mobile/lib/infrastructure/repositories/db.repository.steps.dart index 5815d31978..4b27ce830c 100644 --- a/mobile/lib/infrastructure/repositories/db.repository.steps.dart +++ b/mobile/lib/infrastructure/repositories/db.repository.steps.dart @@ -12,6 +12,7 @@ final class Schema2 extends i0.VersionedSchema { userEntity, remoteAssetEntity, localAssetEntity, + stackEntity, idxLocalAssetChecksum, uQRemoteAssetOwnerChecksum, idxRemoteAssetChecksum, @@ -25,7 +26,6 @@ final class Schema2 extends i0.VersionedSchema { remoteAlbumUserEntity, memoryEntity, memoryAssetEntity, - stackEntity, ]; late final Shape0 userEntity = Shape0( source: i0.VersionedTable( @@ -73,6 +73,7 @@ final class Schema2 extends i0.VersionedSchema { _column_18, _column_19, _column_20, + _column_21, ], attachedDatabase: database, ), @@ -94,9 +95,27 @@ final class Schema2 extends i0.VersionedSchema { _column_11, _column_12, _column_0, - _column_21, - _column_14, _column_22, + _column_14, + _column_23, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape3 stackEntity = Shape3( + source: i0.VersionedTable( + entityName: 'stack_entity', + withoutRowId: true, + isStrict: true, + tableConstraints: [ + 'PRIMARY KEY(id)', + ], + columns: [ + _column_0, + _column_9, + _column_5, + _column_15, + _column_24, ], attachedDatabase: database, ), @@ -108,7 +127,7 @@ final class Schema2 extends i0.VersionedSchema { 'CREATE UNIQUE INDEX UQ_remote_asset_owner_checksum ON remote_asset_entity (checksum, owner_id)'); final i1.Index idxRemoteAssetChecksum = i1.Index('idx_remote_asset_checksum', 'CREATE INDEX idx_remote_asset_checksum ON remote_asset_entity (checksum)'); - late final Shape3 userMetadataEntity = Shape3( + late final Shape4 userMetadataEntity = Shape4( source: i0.VersionedTable( entityName: 'user_metadata_entity', withoutRowId: true, @@ -117,14 +136,14 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(user_id, "key")', ], columns: [ - _column_23, - _column_24, _column_25, + _column_26, + _column_27, ], attachedDatabase: database, ), alias: null); - late final Shape4 partnerEntity = Shape4( + late final Shape5 partnerEntity = Shape5( source: i0.VersionedTable( entityName: 'partner_entity', withoutRowId: true, @@ -133,14 +152,14 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(shared_by_id, shared_with_id)', ], columns: [ - _column_26, - _column_27, _column_28, + _column_29, + _column_30, ], attachedDatabase: database, ), alias: null); - late final Shape5 localAlbumEntity = Shape5( + late final Shape6 localAlbumEntity = Shape6( source: i0.VersionedTable( entityName: 'local_album_entity', withoutRowId: true, @@ -152,14 +171,14 @@ final class Schema2 extends i0.VersionedSchema { _column_0, _column_1, _column_5, - _column_29, - _column_30, _column_31, + _column_32, + _column_33, ], attachedDatabase: database, ), alias: null); - late final Shape6 localAlbumAssetEntity = Shape6( + late final Shape7 localAlbumAssetEntity = Shape7( source: i0.VersionedTable( entityName: 'local_album_asset_entity', withoutRowId: true, @@ -168,13 +187,13 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(asset_id, album_id)', ], columns: [ - _column_32, - _column_33, + _column_34, + _column_35, ], attachedDatabase: database, ), alias: null); - late final Shape7 remoteExifEntity = Shape7( + late final Shape8 remoteExifEntity = Shape8( source: i0.VersionedTable( entityName: 'remote_exif_entity', withoutRowId: true, @@ -183,16 +202,14 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(asset_id)', ], columns: [ - _column_34, - _column_35, _column_36, _column_37, _column_38, _column_39, - _column_11, - _column_10, _column_40, _column_41, + _column_11, + _column_10, _column_42, _column_43, _column_44, @@ -205,11 +222,13 @@ final class Schema2 extends i0.VersionedSchema { _column_51, _column_52, _column_53, + _column_54, + _column_55, ], attachedDatabase: database, ), alias: null); - late final Shape8 remoteAlbumEntity = Shape8( + late final Shape9 remoteAlbumEntity = Shape9( source: i0.VersionedTable( entityName: 'remote_album_entity', withoutRowId: true, @@ -220,18 +239,18 @@ final class Schema2 extends i0.VersionedSchema { columns: [ _column_0, _column_1, - _column_54, + _column_56, _column_9, _column_5, _column_15, - _column_55, - _column_56, _column_57, + _column_58, + _column_59, ], attachedDatabase: database, ), alias: null); - late final Shape6 remoteAlbumAssetEntity = Shape6( + late final Shape7 remoteAlbumAssetEntity = Shape7( source: i0.VersionedTable( entityName: 'remote_album_asset_entity', withoutRowId: true, @@ -240,13 +259,13 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(asset_id, album_id)', ], columns: [ - _column_34, - _column_58, + _column_36, + _column_60, ], attachedDatabase: database, ), alias: null); - late final Shape9 remoteAlbumUserEntity = Shape9( + late final Shape10 remoteAlbumUserEntity = Shape10( source: i0.VersionedTable( entityName: 'remote_album_user_entity', withoutRowId: true, @@ -255,14 +274,14 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(album_id, user_id)', ], columns: [ - _column_58, - _column_23, - _column_59, + _column_60, + _column_25, + _column_61, ], attachedDatabase: database, ), alias: null); - late final Shape10 memoryEntity = Shape10( + late final Shape11 memoryEntity = Shape11( source: i0.VersionedTable( entityName: 'memory_entity', withoutRowId: true, @@ -277,17 +296,17 @@ final class Schema2 extends i0.VersionedSchema { _column_18, _column_15, _column_8, - _column_60, - _column_61, _column_62, _column_63, _column_64, _column_65, + _column_66, + _column_67, ], attachedDatabase: database, ), alias: null); - late final Shape11 memoryAssetEntity = Shape11( + late final Shape12 memoryAssetEntity = Shape12( source: i0.VersionedTable( entityName: 'memory_asset_entity', withoutRowId: true, @@ -296,26 +315,8 @@ final class Schema2 extends i0.VersionedSchema { 'PRIMARY KEY(asset_id, memory_id)', ], columns: [ - _column_34, - _column_66, - ], - attachedDatabase: database, - ), - alias: null); - late final Shape12 stackEntity = Shape12( - source: i0.VersionedTable( - entityName: 'stack_entity', - withoutRowId: true, - isStrict: true, - tableConstraints: [ - 'PRIMARY KEY(id)', - ], - columns: [ - _column_0, - _column_9, - _column_5, - _column_15, - _column_67, + _column_36, + _column_68, ], attachedDatabase: database, ), @@ -405,6 +406,8 @@ class Shape1 extends i0.VersionedTable { columnsByName['live_photo_video_id']! as i1.GeneratedColumn; i1.GeneratedColumn get visibility => columnsByName['visibility']! as i1.GeneratedColumn; + i1.GeneratedColumn get stackId => + columnsByName['stack_id']! as i1.GeneratedColumn; } i1.GeneratedColumn _column_8(String aliasedName) => @@ -452,6 +455,9 @@ i1.GeneratedColumn _column_19(String aliasedName) => i1.GeneratedColumn _column_20(String aliasedName) => i1.GeneratedColumn('visibility', aliasedName, false, type: i1.DriftSqlType.int); +i1.GeneratedColumn _column_21(String aliasedName) => + i1.GeneratedColumn('stack_id', aliasedName, true, + type: i1.DriftSqlType.string); class Shape2 extends i0.VersionedTable { Shape2({required super.source, required super.alias}) : super.aliased(); @@ -479,15 +485,35 @@ class Shape2 extends i0.VersionedTable { columnsByName['orientation']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_21(String aliasedName) => +i1.GeneratedColumn _column_22(String aliasedName) => i1.GeneratedColumn('checksum', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_22(String aliasedName) => +i1.GeneratedColumn _column_23(String aliasedName) => i1.GeneratedColumn('orientation', aliasedName, false, type: i1.DriftSqlType.int, defaultValue: const CustomExpression('0')); class Shape3 extends i0.VersionedTable { Shape3({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get createdAt => + columnsByName['created_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get updatedAt => + columnsByName['updated_at']! as i1.GeneratedColumn; + i1.GeneratedColumn get ownerId => + columnsByName['owner_id']! as i1.GeneratedColumn; + i1.GeneratedColumn get primaryAssetId => + columnsByName['primary_asset_id']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_24(String aliasedName) => + i1.GeneratedColumn('primary_asset_id', aliasedName, false, + type: i1.DriftSqlType.string, + defaultConstraints: i1.GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)')); + +class Shape4 extends i0.VersionedTable { + Shape4({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get userId => columnsByName['user_id']! as i1.GeneratedColumn; i1.GeneratedColumn get key => @@ -496,20 +522,20 @@ class Shape3 extends i0.VersionedTable { columnsByName['value']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_23(String aliasedName) => +i1.GeneratedColumn _column_25(String aliasedName) => i1.GeneratedColumn('user_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES user_entity (id) ON DELETE CASCADE')); -i1.GeneratedColumn _column_24(String aliasedName) => +i1.GeneratedColumn _column_26(String aliasedName) => i1.GeneratedColumn('key', aliasedName, false, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_25(String aliasedName) => +i1.GeneratedColumn _column_27(String aliasedName) => i1.GeneratedColumn('value', aliasedName, false, type: i1.DriftSqlType.blob); -class Shape4 extends i0.VersionedTable { - Shape4({required super.source, required super.alias}) : super.aliased(); +class Shape5 extends i0.VersionedTable { + Shape5({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get sharedById => columnsByName['shared_by_id']! as i1.GeneratedColumn; i1.GeneratedColumn get sharedWithId => @@ -518,25 +544,25 @@ class Shape4 extends i0.VersionedTable { columnsByName['in_timeline']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_26(String aliasedName) => +i1.GeneratedColumn _column_28(String aliasedName) => i1.GeneratedColumn('shared_by_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES user_entity (id) ON DELETE CASCADE')); -i1.GeneratedColumn _column_27(String aliasedName) => +i1.GeneratedColumn _column_29(String aliasedName) => i1.GeneratedColumn('shared_with_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES user_entity (id) ON DELETE CASCADE')); -i1.GeneratedColumn _column_28(String aliasedName) => +i1.GeneratedColumn _column_30(String aliasedName) => i1.GeneratedColumn('in_timeline', aliasedName, false, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("in_timeline" IN (0, 1))'), defaultValue: const CustomExpression('0')); -class Shape5 extends i0.VersionedTable { - Shape5({required super.source, required super.alias}) : super.aliased(); +class Shape6 extends i0.VersionedTable { + Shape6({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get id => columnsByName['id']! as i1.GeneratedColumn; i1.GeneratedColumn get name => @@ -551,42 +577,42 @@ class Shape5 extends i0.VersionedTable { columnsByName['marker']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_29(String aliasedName) => +i1.GeneratedColumn _column_31(String aliasedName) => i1.GeneratedColumn('backup_selection', aliasedName, false, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_30(String aliasedName) => +i1.GeneratedColumn _column_32(String aliasedName) => i1.GeneratedColumn('is_ios_shared_album', aliasedName, false, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("is_ios_shared_album" IN (0, 1))'), defaultValue: const CustomExpression('0')); -i1.GeneratedColumn _column_31(String aliasedName) => +i1.GeneratedColumn _column_33(String aliasedName) => i1.GeneratedColumn('marker', aliasedName, true, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("marker" IN (0, 1))')); -class Shape6 extends i0.VersionedTable { - Shape6({required super.source, required super.alias}) : super.aliased(); +class Shape7 extends i0.VersionedTable { + Shape7({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get assetId => columnsByName['asset_id']! as i1.GeneratedColumn; i1.GeneratedColumn get albumId => columnsByName['album_id']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_32(String aliasedName) => +i1.GeneratedColumn _column_34(String aliasedName) => i1.GeneratedColumn('asset_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES local_asset_entity (id) ON DELETE CASCADE')); -i1.GeneratedColumn _column_33(String aliasedName) => +i1.GeneratedColumn _column_35(String aliasedName) => i1.GeneratedColumn('album_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES local_album_entity (id) ON DELETE CASCADE')); -class Shape7 extends i0.VersionedTable { - Shape7({required super.source, required super.alias}) : super.aliased(); +class Shape8 extends i0.VersionedTable { + Shape8({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get assetId => columnsByName['asset_id']! as i1.GeneratedColumn; i1.GeneratedColumn get city => @@ -633,71 +659,71 @@ class Shape7 extends i0.VersionedTable { columnsByName['projection_type']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_34(String aliasedName) => +i1.GeneratedColumn _column_36(String aliasedName) => i1.GeneratedColumn('asset_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES remote_asset_entity (id) ON DELETE CASCADE')); -i1.GeneratedColumn _column_35(String aliasedName) => +i1.GeneratedColumn _column_37(String aliasedName) => i1.GeneratedColumn('city', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_36(String aliasedName) => +i1.GeneratedColumn _column_38(String aliasedName) => i1.GeneratedColumn('state', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_37(String aliasedName) => +i1.GeneratedColumn _column_39(String aliasedName) => i1.GeneratedColumn('country', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_38(String aliasedName) => +i1.GeneratedColumn _column_40(String aliasedName) => i1.GeneratedColumn('date_time_original', aliasedName, true, type: i1.DriftSqlType.dateTime); -i1.GeneratedColumn _column_39(String aliasedName) => +i1.GeneratedColumn _column_41(String aliasedName) => i1.GeneratedColumn('description', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_40(String aliasedName) => +i1.GeneratedColumn _column_42(String aliasedName) => i1.GeneratedColumn('exposure_time', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_41(String aliasedName) => +i1.GeneratedColumn _column_43(String aliasedName) => i1.GeneratedColumn('f_number', aliasedName, true, type: i1.DriftSqlType.double); -i1.GeneratedColumn _column_42(String aliasedName) => +i1.GeneratedColumn _column_44(String aliasedName) => i1.GeneratedColumn('file_size', aliasedName, true, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_43(String aliasedName) => +i1.GeneratedColumn _column_45(String aliasedName) => i1.GeneratedColumn('focal_length', aliasedName, true, type: i1.DriftSqlType.double); -i1.GeneratedColumn _column_44(String aliasedName) => +i1.GeneratedColumn _column_46(String aliasedName) => i1.GeneratedColumn('latitude', aliasedName, true, type: i1.DriftSqlType.double); -i1.GeneratedColumn _column_45(String aliasedName) => +i1.GeneratedColumn _column_47(String aliasedName) => i1.GeneratedColumn('longitude', aliasedName, true, type: i1.DriftSqlType.double); -i1.GeneratedColumn _column_46(String aliasedName) => +i1.GeneratedColumn _column_48(String aliasedName) => i1.GeneratedColumn('iso', aliasedName, true, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_47(String aliasedName) => +i1.GeneratedColumn _column_49(String aliasedName) => i1.GeneratedColumn('make', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_48(String aliasedName) => +i1.GeneratedColumn _column_50(String aliasedName) => i1.GeneratedColumn('model', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_49(String aliasedName) => +i1.GeneratedColumn _column_51(String aliasedName) => i1.GeneratedColumn('lens', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_50(String aliasedName) => +i1.GeneratedColumn _column_52(String aliasedName) => i1.GeneratedColumn('orientation', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_51(String aliasedName) => +i1.GeneratedColumn _column_53(String aliasedName) => i1.GeneratedColumn('time_zone', aliasedName, true, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_52(String aliasedName) => +i1.GeneratedColumn _column_54(String aliasedName) => i1.GeneratedColumn('rating', aliasedName, true, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_53(String aliasedName) => +i1.GeneratedColumn _column_55(String aliasedName) => i1.GeneratedColumn('projection_type', aliasedName, true, type: i1.DriftSqlType.string); -class Shape8 extends i0.VersionedTable { - Shape8({required super.source, required super.alias}) : super.aliased(); +class Shape9 extends i0.VersionedTable { + Shape9({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get id => columnsByName['id']! as i1.GeneratedColumn; i1.GeneratedColumn get name => @@ -718,32 +744,32 @@ class Shape8 extends i0.VersionedTable { columnsByName['order']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_54(String aliasedName) => +i1.GeneratedColumn _column_56(String aliasedName) => i1.GeneratedColumn('description', aliasedName, false, type: i1.DriftSqlType.string, defaultValue: const CustomExpression('\'\'')); -i1.GeneratedColumn _column_55(String aliasedName) => +i1.GeneratedColumn _column_57(String aliasedName) => i1.GeneratedColumn('thumbnail_asset_id', aliasedName, true, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES remote_asset_entity (id) ON DELETE SET NULL')); -i1.GeneratedColumn _column_56(String aliasedName) => +i1.GeneratedColumn _column_58(String aliasedName) => i1.GeneratedColumn('is_activity_enabled', aliasedName, false, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("is_activity_enabled" IN (0, 1))'), defaultValue: const CustomExpression('1')); -i1.GeneratedColumn _column_57(String aliasedName) => +i1.GeneratedColumn _column_59(String aliasedName) => i1.GeneratedColumn('order', aliasedName, false, type: i1.DriftSqlType.int); -i1.GeneratedColumn _column_58(String aliasedName) => +i1.GeneratedColumn _column_60(String aliasedName) => i1.GeneratedColumn('album_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES remote_album_entity (id) ON DELETE CASCADE')); -class Shape9 extends i0.VersionedTable { - Shape9({required super.source, required super.alias}) : super.aliased(); +class Shape10 extends i0.VersionedTable { + Shape10({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get albumId => columnsByName['album_id']! as i1.GeneratedColumn; i1.GeneratedColumn get userId => @@ -752,12 +778,12 @@ class Shape9 extends i0.VersionedTable { columnsByName['role']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_59(String aliasedName) => +i1.GeneratedColumn _column_61(String aliasedName) => i1.GeneratedColumn('role', aliasedName, false, type: i1.DriftSqlType.int); -class Shape10 extends i0.VersionedTable { - Shape10({required super.source, required super.alias}) : super.aliased(); +class Shape11 extends i0.VersionedTable { + Shape11({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get id => columnsByName['id']! as i1.GeneratedColumn; i1.GeneratedColumn get createdAt => @@ -784,61 +810,41 @@ class Shape10 extends i0.VersionedTable { columnsByName['hide_at']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_60(String aliasedName) => +i1.GeneratedColumn _column_62(String aliasedName) => i1.GeneratedColumn('data', aliasedName, false, type: i1.DriftSqlType.string); -i1.GeneratedColumn _column_61(String aliasedName) => +i1.GeneratedColumn _column_63(String aliasedName) => i1.GeneratedColumn('is_saved', aliasedName, false, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("is_saved" IN (0, 1))'), defaultValue: const CustomExpression('0')); -i1.GeneratedColumn _column_62(String aliasedName) => +i1.GeneratedColumn _column_64(String aliasedName) => i1.GeneratedColumn('memory_at', aliasedName, false, type: i1.DriftSqlType.dateTime); -i1.GeneratedColumn _column_63(String aliasedName) => +i1.GeneratedColumn _column_65(String aliasedName) => i1.GeneratedColumn('seen_at', aliasedName, true, type: i1.DriftSqlType.dateTime); -i1.GeneratedColumn _column_64(String aliasedName) => +i1.GeneratedColumn _column_66(String aliasedName) => i1.GeneratedColumn('show_at', aliasedName, true, type: i1.DriftSqlType.dateTime); -i1.GeneratedColumn _column_65(String aliasedName) => +i1.GeneratedColumn _column_67(String aliasedName) => i1.GeneratedColumn('hide_at', aliasedName, true, type: i1.DriftSqlType.dateTime); -class Shape11 extends i0.VersionedTable { - Shape11({required super.source, required super.alias}) : super.aliased(); +class Shape12 extends i0.VersionedTable { + Shape12({required super.source, required super.alias}) : super.aliased(); i1.GeneratedColumn get assetId => columnsByName['asset_id']! as i1.GeneratedColumn; i1.GeneratedColumn get memoryId => columnsByName['memory_id']! as i1.GeneratedColumn; } -i1.GeneratedColumn _column_66(String aliasedName) => +i1.GeneratedColumn _column_68(String aliasedName) => i1.GeneratedColumn('memory_id', aliasedName, false, type: i1.DriftSqlType.string, defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'REFERENCES memory_entity (id) ON DELETE CASCADE')); - -class Shape12 extends i0.VersionedTable { - Shape12({required super.source, required super.alias}) : super.aliased(); - i1.GeneratedColumn get id => - columnsByName['id']! as i1.GeneratedColumn; - i1.GeneratedColumn get createdAt => - columnsByName['created_at']! as i1.GeneratedColumn; - i1.GeneratedColumn get updatedAt => - columnsByName['updated_at']! as i1.GeneratedColumn; - i1.GeneratedColumn get ownerId => - columnsByName['owner_id']! as i1.GeneratedColumn; - i1.GeneratedColumn get primaryAssetId => - columnsByName['primary_asset_id']! as i1.GeneratedColumn; -} - -i1.GeneratedColumn _column_67(String aliasedName) => - i1.GeneratedColumn('primary_asset_id', aliasedName, false, - type: i1.DriftSqlType.string, - defaultConstraints: i1.GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, }) { diff --git a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart index 1f6f1b0891..28c229b46b 100644 --- a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart @@ -1,11 +1,13 @@ import 'package:drift/drift.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/models/exif.model.dart'; +import 'package:immich_mobile/domain/models/stack.model.dart'; import 'package:immich_mobile/infrastructure/entities/exif.entity.dart' hide ExifInfo; import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'; +import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; @@ -30,25 +32,66 @@ class RemoteAssetRepository extends DriftDatabaseRepository { } Stream watchAsset(String id) { - final query = _db.remoteAssetEntity - .select() - .addColumns([_db.localAssetEntity.id]).join([ + final stackCountRef = _db.stackEntity.id.count(); + + final query = _db.remoteAssetEntity.select().addColumns([ + _db.localAssetEntity.id, + _db.stackEntity.primaryAssetId, + stackCountRef, + ]).join([ leftOuterJoin( _db.localAssetEntity, _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), useColumns: false, ), + leftOuterJoin( + _db.stackEntity, + _db.stackEntity.primaryAssetId.equalsExp(_db.remoteAssetEntity.id), + useColumns: false, + ), + leftOuterJoin( + _db.remoteAssetEntity.createAlias('stacked_assets'), + _db.stackEntity.id.equalsExp( + _db.remoteAssetEntity.createAlias('stacked_assets').stackId, + ), + useColumns: false, + ), ]) - ..where(_db.remoteAssetEntity.id.equals(id)); + ..where(_db.remoteAssetEntity.id.equals(id)) + ..groupBy([ + _db.remoteAssetEntity.id, + _db.localAssetEntity.id, + _db.stackEntity.primaryAssetId, + ]); return query.map((row) { final asset = row.readTable(_db.remoteAssetEntity).toDto(); + final primaryAssetId = row.read(_db.stackEntity.primaryAssetId); + final stackCount = + primaryAssetId == id ? (row.read(stackCountRef) ?? 0) : 0; + return asset.copyWith( localId: row.read(_db.localAssetEntity.id), + stackCount: stackCount, ); }).watchSingleOrNull(); } + Future> getStackChildren(RemoteAsset asset) { + if (asset.stackId == null) { + return Future.value([]); + } + + final query = _db.remoteAssetEntity.select() + ..where( + (row) => + row.stackId.equals(asset.stackId!) & row.id.equals(asset.id).not(), + ) + ..orderBy([(row) => OrderingTerm.desc(row.createdAt)]); + + return query.map((row) => row.toDto()).get(); + } + Future getExif(String id) { return _db.managers.remoteExifEntity .filter((row) => row.assetId.id.equals(id)) @@ -146,4 +189,53 @@ class RemoteAssetRepository extends DriftDatabaseRepository { } }); } + + Future stack(String userId, StackResponse stack) { + return _db.transaction(() async { + final stackIds = await _db.managers.stackEntity + .filter((row) => row.primaryAssetId.id.isIn(stack.assetIds)) + .map((row) => row.id) + .get(); + + await _db.stackEntity.deleteWhere((row) => row.id.isIn(stackIds)); + + await _db.batch((batch) { + final companion = StackEntityCompanion( + ownerId: Value(userId), + primaryAssetId: Value(stack.primaryAssetId), + ); + + batch.insert( + _db.stackEntity, + companion.copyWith(id: Value(stack.id)), + onConflict: DoUpdate((_) => companion), + ); + + for (final assetId in stack.assetIds) { + batch.update( + _db.remoteAssetEntity, + RemoteAssetEntityCompanion( + stackId: Value(stack.id), + ), + where: (e) => e.id.equals(assetId), + ); + } + }); + }); + } + + Future unStack(List stackIds) { + return _db.transaction(() async { + await _db.stackEntity.deleteWhere((row) => row.id.isIn(stackIds)); + + // TODO: delete this after adding foreign key on stackId + await _db.batch((batch) { + batch.update( + _db.remoteAssetEntity, + const RemoteAssetEntityCompanion(stackId: Value(null)), + where: (e) => e.stackId.isIn(stackIds), + ); + }); + }); + } } diff --git a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart index f3f26bb01f..d28c68ed78 100644 --- a/mobile/lib/infrastructure/repositories/sync_stream.repository.dart +++ b/mobile/lib/infrastructure/repositories/sync_stream.repository.dart @@ -137,6 +137,7 @@ class SyncStreamRepository extends DriftDatabaseRepository { deletedAt: Value(asset.deletedAt), visibility: Value(asset.visibility.toAssetVisibility()), livePhotoVideoId: Value(asset.livePhotoVideoId), + stackId: Value(asset.stackId), ); batch.insert( diff --git a/mobile/lib/infrastructure/repositories/timeline.repository.dart b/mobile/lib/infrastructure/repositories/timeline.repository.dart index a6d89b5e8e..0c3eee59af 100644 --- a/mobile/lib/infrastructure/repositories/timeline.repository.dart +++ b/mobile/lib/infrastructure/repositories/timeline.repository.dart @@ -89,6 +89,8 @@ class DriftTimelineRepository extends DriftDatabaseRepository { isFavorite: row.isFavorite, durationInSeconds: row.durationInSeconds, livePhotoVideoId: row.livePhotoVideoId, + stackId: row.stackId, + stackCount: row.stackCount, ) : LocalAsset( id: row.localId!, diff --git a/mobile/lib/presentation/pages/dev/main_timeline.page.dart b/mobile/lib/presentation/pages/dev/main_timeline.page.dart index 7216b638e1..0582399eaf 100644 --- a/mobile/lib/presentation/pages/dev/main_timeline.page.dart +++ b/mobile/lib/presentation/pages/dev/main_timeline.page.dart @@ -13,7 +13,7 @@ class MainTimelinePage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final memoryLaneProvider = ref.watch(driftMemoryFutureProvider); - return memoryLaneProvider.when( + return memoryLaneProvider.maybeWhen( data: (memories) { return memories.isEmpty ? const Timeline(showStorageIndicator: true) @@ -26,8 +26,7 @@ class MainTimelinePage extends ConsumerWidget { showStorageIndicator: true, ); }, - loading: () => const Timeline(showStorageIndicator: true), - error: (error, stackTrace) => const Timeline(showStorageIndicator: true), + orElse: () => const Timeline(showStorageIndicator: true), ); } } diff --git a/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart index dc42eb96f1..13782c0098 100644 --- a/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/stack_action_button.widget.dart @@ -1,16 +1,56 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/providers/user.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; class StackActionButton extends ConsumerWidget { - const StackActionButton({super.key}); + final ActionSource source; + + const StackActionButton({super.key, required this.source}); + + void _onTap(BuildContext context, WidgetRef ref) async { + if (!context.mounted) { + return; + } + + final user = ref.watch(currentUserProvider); + if (user == null) { + throw Exception('User must be logged in to access stack action'); + } + + final result = + await ref.read(actionProvider.notifier).stack(user.id, source); + ref.read(multiSelectProvider.notifier).reset(); + + final successMessage = 'stack_action_prompt'.t( + context: context, + args: {'count': result.count.toString()}, + ); + + if (context.mounted) { + ImmichToast.show( + context: context, + msg: result.success + ? successMessage + : 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: result.success ? ToastType.success : ToastType.error, + ); + } + } @override Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( iconData: Icons.filter_none_rounded, label: "stack".t(context: context), + onPressed: () => _onTap(context, ref), ); } } diff --git a/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart new file mode 100644 index 0000000000..c2757043a3 --- /dev/null +++ b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/enums.dart'; +import 'package:immich_mobile/extensions/translate_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/action.provider.dart'; +import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_toast.dart'; + +class UnStackActionButton extends ConsumerWidget { + final ActionSource source; + + const UnStackActionButton({super.key, required this.source}); + + void _onTap(BuildContext context, WidgetRef ref) async { + if (!context.mounted) { + return; + } + + final result = await ref.read(actionProvider.notifier).unStack(source); + ref.read(multiSelectProvider.notifier).reset(); + + final successMessage = 'unstack_action_prompt'.t( + context: context, + args: {'count': result.count.toString()}, + ); + + if (context.mounted) { + ImmichToast.show( + context: context, + msg: result.success + ? successMessage + : 'scaffold_body_error_occurred'.t(context: context), + gravity: ToastGravity.BOTTOM, + toastType: result.success ? ToastType.success : ToastType.error, + ); + } + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + return BaseActionButton( + iconData: Icons.filter_none_rounded, + label: "unstack".t(context: context), + onPressed: () => _onTap(context, ref), + ); + } +} diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart new file mode 100644 index 0000000000..cb4e02b56c --- /dev/null +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.provider.dart @@ -0,0 +1,24 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; + +class StackChildrenNotifier + extends AutoDisposeFamilyAsyncNotifier, BaseAsset?> { + @override + Future> build(BaseAsset? asset) async { + if (asset == null || + asset is! RemoteAsset || + asset.stackId == null || + // The stackCount check is to ensure we only fetch stacks for timelines that have stacks + asset.stackCount == 0) { + return const []; + } + + return ref.watch(assetServiceProvider).getStack(asset); + } +} + +final stackChildrenNotifier = AsyncNotifierProvider.autoDispose + .family, BaseAsset?>( + StackChildrenNotifier.new, +); diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart new file mode 100644 index 0000000000..8b3d0c6575 --- /dev/null +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_stack.widget.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_stack.provider.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart'; +import 'package:immich_mobile/presentation/widgets/images/image_provider.dart'; +import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; + +class AssetStackRow extends ConsumerWidget { + const AssetStackRow({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + int opacity = ref.watch( + assetViewerProvider.select((state) => state.backgroundOpacity), + ); + final showControls = + ref.watch(assetViewerProvider.select((s) => s.showingControls)); + + if (!showControls) { + opacity = 0; + } + + final asset = ref.watch(assetViewerProvider.select((s) => s.currentAsset)); + + return IgnorePointer( + ignoring: opacity < 255, + child: AnimatedOpacity( + opacity: opacity / 255, + duration: Durations.short2, + child: ref.watch(stackChildrenNotifier(asset)).when( + data: (state) => SizedBox.square( + dimension: 80, + child: _StackList(stack: state), + ), + error: (_, __) => const SizedBox.shrink(), + loading: () => const SizedBox.shrink(), + ), + ), + ); + } +} + +class _StackList extends ConsumerWidget { + final List stack; + + const _StackList({required this.stack}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ListView.builder( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.only( + left: 5, + right: 5, + bottom: 30, + ), + itemCount: stack.length, + itemBuilder: (ctx, index) { + final asset = stack[index]; + return Padding( + padding: const EdgeInsets.only(right: 5), + child: GestureDetector( + onTap: () { + ref.read(assetViewerProvider.notifier).setStackIndex(index); + ref.read(currentAssetNotifier.notifier).setAsset(asset); + }, + child: Container( + height: 60, + width: 60, + decoration: index == + ref.watch(assetViewerProvider.select((s) => s.stackIndex)) + ? const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6)), + border: Border.fromBorderSide( + BorderSide(color: Colors.white, width: 2), + ), + ) + : const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6)), + border: null, + ), + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(4)), + child: Stack( + fit: StackFit.expand, + children: [ + Image( + fit: BoxFit.cover, + image: getThumbnailImageProvider( + remoteId: asset.id, + size: const Size.square(60), + ), + ), + if (asset.isVideo) + const Icon( + Icons.play_circle_outline_rounded, + color: Colors.white, + size: 16, + shadows: [ + Shadow( + blurRadius: 5.0, + color: Color.fromRGBO(0, 0, 0, 0.6), + offset: Offset(0.0, 0.0), + ), + ], + ), + ], + ), + ), + ), + ), + ); + }, + ); + } +} diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart index 1c0f28413a..50f4a09197 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart @@ -5,10 +5,13 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/scroll_extensions.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_stack.provider.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_stack.widget.dart'; import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart'; import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_bar.widget.dart'; import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet.widget.dart'; @@ -85,6 +88,7 @@ class _AssetViewerState extends ConsumerState { double previousExtent = _kBottomSheetMinimumExtent; Offset dragDownPosition = Offset.zero; int totalAssets = 0; + int stackIndex = 0; BuildContext? scaffoldContext; Map videoPlayerKeys = {}; @@ -167,6 +171,10 @@ class _AssetViewerState extends ConsumerState { void _onAssetChanged(int index) { final asset = ref.read(timelineServiceProvider).getAsset(index); + // Always holds the current asset from the timeline + ref.read(assetViewerProvider.notifier).setAsset(asset); + // The currentAssetNotifier actually holds the current asset that is displayed + // which could be stack children as well ref.read(currentAssetNotifier.notifier).setAsset(asset); if (asset.isVideo || asset.isMotionPhoto) { ref.read(videoPlaybackValueProvider.notifier).reset(); @@ -488,7 +496,12 @@ class _AssetViewerState extends ConsumerState { ImageChunkEvent? progress, int index, ) { - final asset = ref.read(timelineServiceProvider).getAsset(index); + BaseAsset asset = ref.read(timelineServiceProvider).getAsset(index); + final stackChildren = ref.read(stackChildrenNotifier(asset)).valueOrNull; + if (stackChildren != null && stackChildren.isNotEmpty) { + asset = stackChildren + .elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); + } return Container( width: double.infinity, height: double.infinity, @@ -516,9 +529,14 @@ class _AssetViewerState extends ConsumerState { PhotoViewGalleryPageOptions _assetBuilder(BuildContext ctx, int index) { scaffoldContext ??= ctx; - final asset = ref.read(timelineServiceProvider).getAsset(index); - final isPlayingMotionVideo = ref.read(isPlayingMotionVideoProvider); + BaseAsset asset = ref.read(timelineServiceProvider).getAsset(index); + final stackChildren = ref.read(stackChildrenNotifier(asset)).valueOrNull; + if (stackChildren != null && stackChildren.isNotEmpty) { + asset = stackChildren + .elementAt(ref.read(assetViewerProvider.select((s) => s.stackIndex))); + } + final isPlayingMotionVideo = ref.read(isPlayingMotionVideoProvider); if (asset.isImage && !isPlayingMotionVideo) { return _imageBuilder(ctx, asset); } @@ -604,6 +622,7 @@ class _AssetViewerState extends ConsumerState { // Using multiple selectors to avoid unnecessary rebuilds for other state changes ref.watch(assetViewerProvider.select((s) => s.showingBottomSheet)); ref.watch(assetViewerProvider.select((s) => s.backgroundOpacity)); + ref.watch(assetViewerProvider.select((s) => s.stackIndex)); ref.watch(isPlayingMotionVideoProvider); // Listen for casting changes and send initial asset to the cast provider @@ -645,7 +664,17 @@ class _AssetViewerState extends ConsumerState { backgroundDecoration: BoxDecoration(color: backgroundColor), enablePanAlways: true, ), - bottomNavigationBar: const ViewerBottomBar(), + bottomNavigationBar: showingBottomSheet + ? const SizedBox.shrink() + : const Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + AssetStackRow(), + ViewerBottomBar(), + ], + ), ), ); } diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart index 020d1d9b2c..825b637e8d 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.state.dart @@ -1,26 +1,40 @@ +import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +class ViewerOpenBottomSheetEvent extends Event { + const ViewerOpenBottomSheetEvent(); +} + class AssetViewerState { final int backgroundOpacity; final bool showingBottomSheet; final bool showingControls; + final BaseAsset? currentAsset; + final int stackIndex; const AssetViewerState({ this.backgroundOpacity = 255, this.showingBottomSheet = false, this.showingControls = true, + this.currentAsset, + this.stackIndex = 0, }); AssetViewerState copyWith({ int? backgroundOpacity, bool? showingBottomSheet, bool? showingControls, + BaseAsset? currentAsset, + int? stackIndex, }) { return AssetViewerState( backgroundOpacity: backgroundOpacity ?? this.backgroundOpacity, showingBottomSheet: showingBottomSheet ?? this.showingBottomSheet, showingControls: showingControls ?? this.showingControls, + currentAsset: currentAsset ?? this.currentAsset, + stackIndex: stackIndex ?? this.stackIndex, ); } @@ -36,14 +50,18 @@ class AssetViewerState { return other is AssetViewerState && other.backgroundOpacity == backgroundOpacity && other.showingBottomSheet == showingBottomSheet && - other.showingControls == showingControls; + other.showingControls == showingControls && + other.currentAsset == currentAsset && + other.stackIndex == stackIndex; } @override int get hashCode => backgroundOpacity.hashCode ^ showingBottomSheet.hashCode ^ - showingControls.hashCode; + showingControls.hashCode ^ + currentAsset.hashCode ^ + stackIndex.hashCode; } class AssetViewerStateNotifier extends AutoDisposeNotifier { @@ -52,6 +70,10 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier { return const AssetViewerState(); } + void setAsset(BaseAsset? asset) { + state = state.copyWith(currentAsset: asset, stackIndex: 0); + } + void setOpacity(int opacity) { state = state.copyWith( backgroundOpacity: opacity, @@ -76,6 +98,10 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier { void toggleControls() { state = state.copyWith(showingControls: !state.showingControls); } + + void setStackIndex(int index) { + state = state.copyWith(stackIndex: index); + } } final assetViewerProvider = diff --git a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart index 7b1175e8be..a3d24ec8ee 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart @@ -49,7 +49,7 @@ class ArchiveBottomSheet extends ConsumerWidget { const MoveToLockFolderActionButton( source: ActionSource.timeline, ), - const StackActionButton(), + const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart index 0615a857a9..eefe19194c 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart @@ -49,7 +49,7 @@ class FavoriteBottomSheet extends ConsumerWidget { const MoveToLockFolderActionButton( source: ActionSource.timeline, ), - const StackActionButton(), + const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart index 61414252da..f9a9dd3203 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart @@ -49,7 +49,7 @@ class GeneralBottomSheet extends ConsumerWidget { const MoveToLockFolderActionButton( source: ActionSource.timeline, ), - const StackActionButton(), + const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart index c2d0d5c85a..b5fecdf7a4 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart @@ -52,7 +52,7 @@ class RemoteAlbumBottomSheet extends ConsumerWidget { const MoveToLockFolderActionButton( source: ActionSource.timeline, ), - const StackActionButton(), + const StackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart index 7e3776adb2..ce3d39629f 100644 --- a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart +++ b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart @@ -53,6 +53,9 @@ class ThumbnailTile extends ConsumerWidget { ) : const BoxDecoration(); + final hasStack = + asset is RemoteAsset && (asset as RemoteAsset).stackCount > 0; + return Stack( children: [ AnimatedContainer( @@ -75,6 +78,19 @@ class ThumbnailTile extends ConsumerWidget { ), ), ), + if (hasStack) + Align( + alignment: Alignment.topRight, + child: Padding( + padding: EdgeInsets.only( + right: 10.0, + top: asset.isVideo ? 24.0 : 6.0, + ), + child: _StackIndicator( + stackCount: (asset as RemoteAsset).stackCount, + ), + ), + ), if (asset.isVideo) Align( alignment: Alignment.topRight, @@ -182,6 +198,40 @@ class _SelectionIndicator extends StatelessWidget { } } +class _StackIndicator extends StatelessWidget { + final int stackCount; + + const _StackIndicator({required this.stackCount}); + + @override + Widget build(BuildContext context) { + return Row( + spacing: 3, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + // CrossAxisAlignment.start looks more centered vertically than CrossAxisAlignment.center + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + stackCount.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + shadows: [ + Shadow( + blurRadius: 5.0, + color: Color.fromRGBO(0, 0, 0, 0.6), + ), + ], + ), + ), + const _TileOverlayIcon(Icons.burst_mode_rounded), + ], + ); + } +} + class _VideoIndicator extends StatelessWidget { final Duration duration; const _VideoIndicator(this.duration); @@ -192,8 +242,8 @@ class _VideoIndicator extends StatelessWidget { spacing: 3, mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, - // CrossAxisAlignment.end looks more centered vertically than CrossAxisAlignment.center - crossAxisAlignment: CrossAxisAlignment.end, + // CrossAxisAlignment.start looks more centered vertically than CrossAxisAlignment.center + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( duration.format(), diff --git a/mobile/lib/presentation/widgets/timeline/timeline.state.dart b/mobile/lib/presentation/widgets/timeline/timeline.state.dart index 91003fb1a1..6faa4da9f7 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.state.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.state.dart @@ -15,6 +15,7 @@ class TimelineArgs { final double spacing; final int columnCount; final bool showStorageIndicator; + final bool withStack; final GroupAssetsBy? groupBy; const TimelineArgs({ @@ -23,6 +24,7 @@ class TimelineArgs { this.spacing = kTimelineSpacing, this.columnCount = kTimelineColumnCount, this.showStorageIndicator = false, + this.withStack = false, this.groupBy, }); @@ -33,6 +35,7 @@ class TimelineArgs { maxHeight == other.maxHeight && columnCount == other.columnCount && showStorageIndicator == other.showStorageIndicator && + withStack == other.withStack && groupBy == other.groupBy; } @@ -43,6 +46,7 @@ class TimelineArgs { spacing.hashCode ^ columnCount.hashCode ^ showStorageIndicator.hashCode ^ + withStack.hashCode ^ groupBy.hashCode; } diff --git a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart index d279937417..873908832b 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart @@ -28,6 +28,7 @@ class Timeline extends StatelessWidget { this.topSliverWidget, this.topSliverWidgetHeight, this.showStorageIndicator = false, + this.withStack = false, this.appBar = const ImmichSliverAppBar( floating: true, pinned: false, @@ -42,6 +43,7 @@ class Timeline extends StatelessWidget { final bool showStorageIndicator; final Widget? appBar; final Widget? bottomSheet; + final bool withStack; final GroupAssetsBy? groupBy; @override @@ -58,6 +60,7 @@ class Timeline extends StatelessWidget { settingsProvider.select((s) => s.get(Setting.tilesPerRow)), ), showStorageIndicator: showStorageIndicator, + withStack: withStack, groupBy: groupBy, ), ), diff --git a/mobile/lib/providers/infrastructure/action.provider.dart b/mobile/lib/providers/infrastructure/action.provider.dart index b53417d021..456b072a39 100644 --- a/mobile/lib/providers/infrastructure/action.provider.dart +++ b/mobile/lib/providers/infrastructure/action.provider.dart @@ -50,7 +50,7 @@ class ActionNotifier extends Notifier { return _getIdsForSource(source).toIds().toList(growable: false); } - List _getOwnedRemoteForSource(ActionSource source) { + List _getOwnedRemoteIdsForSource(ActionSource source) { final ownerId = ref.read(currentUserProvider)?.id; return _getIdsForSource(source) .ownedAssets(ownerId) @@ -58,6 +58,20 @@ class ActionNotifier extends Notifier { .toList(growable: false); } + List _getOwnedRemoteAssetsForSource(ActionSource source) { + final ownerId = ref.read(currentUserProvider)?.id; + return _getIdsForSource(source).ownedAssets(ownerId).toList(); + } + + Iterable _getIdsForSource(ActionSource source) { + final Set assets = _getAssets(source); + return switch (T) { + const (RemoteAsset) => assets.whereType(), + const (LocalAsset) => assets.whereType(), + _ => const [], + } as Iterable; + } + Set _getAssets(ActionSource source) { return switch (source) { ActionSource.timeline => ref.read(multiSelectProvider).selectedAssets, @@ -68,15 +82,6 @@ class ActionNotifier extends Notifier { }; } - Iterable _getIdsForSource(ActionSource source) { - final Set assets = _getAssets(source); - return switch (T) { - const (RemoteAsset) => assets.whereType(), - const (LocalAsset) => assets.whereType(), - _ => const [], - } as Iterable; - } - Future shareLink( ActionSource source, BuildContext context, @@ -96,7 +101,7 @@ class ActionNotifier extends Notifier { } Future favorite(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.favorite(ids); return ActionResult(count: ids.length, success: true); @@ -111,7 +116,7 @@ class ActionNotifier extends Notifier { } Future unFavorite(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.unFavorite(ids); return ActionResult(count: ids.length, success: true); @@ -126,7 +131,7 @@ class ActionNotifier extends Notifier { } Future archive(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.archive(ids); return ActionResult(count: ids.length, success: true); @@ -141,7 +146,7 @@ class ActionNotifier extends Notifier { } Future unArchive(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.unArchive(ids); return ActionResult(count: ids.length, success: true); @@ -156,7 +161,7 @@ class ActionNotifier extends Notifier { } Future moveToLockFolder(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.moveToLockFolder(ids); return ActionResult(count: ids.length, success: true); @@ -171,7 +176,7 @@ class ActionNotifier extends Notifier { } Future removeFromLockFolder(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.removeFromLockFolder(ids); return ActionResult(count: ids.length, success: true); @@ -186,7 +191,7 @@ class ActionNotifier extends Notifier { } Future trash(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.trash(ids); return ActionResult(count: ids.length, success: true); @@ -201,7 +206,7 @@ class ActionNotifier extends Notifier { } Future delete(ActionSource source) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { await _service.delete(ids); return ActionResult(count: ids.length, success: true); @@ -234,7 +239,7 @@ class ActionNotifier extends Notifier { ActionSource source, BuildContext context, ) async { - final ids = _getOwnedRemoteForSource(source); + final ids = _getOwnedRemoteIdsForSource(source); try { final isEdited = await _service.editLocation(ids, context); if (!isEdited) { @@ -270,6 +275,35 @@ class ActionNotifier extends Notifier { } } + Future stack(String userId, ActionSource source) async { + final ids = _getOwnedRemoteIdsForSource(source); + try { + await _service.stack(userId, ids); + return ActionResult(count: ids.length, success: true); + } catch (error, stack) { + _logger.severe('Failed to stack assets', error, stack); + return ActionResult( + count: ids.length, + success: false, + error: error.toString(), + ); + } + } + + Future unStack(ActionSource source) async { + final assets = _getOwnedRemoteAssetsForSource(source); + try { + await _service.unStack(assets.map((e) => e.stackId).nonNulls.toList()); + return ActionResult(count: assets.length, success: true); + } catch (error, stack) { + _logger.severe('Failed to unstack assets', error, stack); + return ActionResult( + count: assets.length, + success: false, + ); + } + } + Future shareAssets(ActionSource source) async { final ids = _getAssets(source).toList(growable: false); diff --git a/mobile/lib/repositories/asset_api.repository.dart b/mobile/lib/repositories/asset_api.repository.dart index cd49369a2a..4c854973b1 100644 --- a/mobile/lib/repositories/asset_api.repository.dart +++ b/mobile/lib/repositories/asset_api.repository.dart @@ -1,6 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:http/http.dart'; import 'package:immich_mobile/constants/enums.dart'; +import 'package:immich_mobile/domain/models/stack.model.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/repositories/api.repository.dart'; @@ -11,14 +12,16 @@ final assetApiRepositoryProvider = Provider( (ref) => AssetApiRepository( ref.watch(apiServiceProvider).assetsApi, ref.watch(apiServiceProvider).searchApi, + ref.watch(apiServiceProvider).stacksApi, ), ); class AssetApiRepository extends ApiRepository { final AssetsApi _api; final SearchApi _searchApi; + final StacksApi _stacksApi; - AssetApiRepository(this._api, this._searchApi); + AssetApiRepository(this._api, this._searchApi, this._stacksApi); Future update(String id, {String? description}) async { final response = await checkNull( @@ -84,6 +87,17 @@ class AssetApiRepository extends ApiRepository { ); } + Future stack(List ids) async { + final responseDto = + await checkNull(_stacksApi.createStack(StackCreateDto(assetIds: ids))); + + return responseDto.toStack(); + } + + Future unStack(List ids) async { + return _stacksApi.deleteStacks(BulkIdsDto(ids: ids)); + } + Future downloadAsset(String id) { return _api.downloadAssetWithHttpInfo(id); } @@ -102,3 +116,13 @@ class AssetApiRepository extends ApiRepository { return response.originalMimeType; } } + +extension on StackResponseDto { + StackResponse toStack() { + return StackResponse( + id: id, + primaryAssetId: primaryAssetId, + assetIds: assets.map((asset) => asset.id).toList(), + ); + } +} diff --git a/mobile/lib/services/action.service.dart b/mobile/lib/services/action.service.dart index 9559c5d316..adefd5da16 100644 --- a/mobile/lib/services/action.service.dart +++ b/mobile/lib/services/action.service.dart @@ -166,6 +166,16 @@ class ActionService { return removedCount; } + Future stack(String userId, List remoteIds) async { + final stack = await _assetApiRepository.stack(remoteIds); + await _remoteAssetRepository.stack(userId, stack); + } + + Future unStack(List stackIds) async { + await _remoteAssetRepository.unStack(stackIds); + await _assetApiRepository.unStack(stackIds); + } + Future shareAssets(List assets) { return _assetMediaRepository.shareAssets(assets); } diff --git a/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart b/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart index faaccfa51a..eace57fe5c 100644 --- a/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/mesmerizing_sliver_app_bar.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; diff --git a/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart b/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart index 2d35a6702b..41eed09d8c 100644 --- a/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart +++ b/mobile/lib/widgets/common/remote_album_sliver_app_bar.dart @@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/timeline.model.dart'; import 'package:immich_mobile/domain/services/timeline.service.dart'; import 'package:immich_mobile/domain/utils/event_stream.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; diff --git a/mobile/lib/widgets/map/map_thumbnail.dart b/mobile/lib/widgets/map/map_thumbnail.dart index 06935cd4b5..1e4b061be6 100644 --- a/mobile/lib/widgets/map/map_thumbnail.dart +++ b/mobile/lib/widgets/map/map_thumbnail.dart @@ -63,8 +63,14 @@ class MapThumbnail extends HookConsumerWidget { } Future onStyleLoaded() async { - if (showMarkerPin && controller.value != null) { - await controller.value?.addMarkerAtLatLng(centre); + try { + if (showMarkerPin && controller.value != null) { + await controller.value?.addMarkerAtLatLng(centre); + } + } finally { + // Calling methods on the controller after it is disposed will throw an error + // We do not have a way to check if the controller is disposed for now + // https://github.com/maplibre/flutter-maplibre-gl/issues/192 } styleLoaded.value = true; } diff --git a/mobile/test/drift/main/generated/schema_v1.dart b/mobile/test/drift/main/generated/schema_v1.dart index 0172201921..38dbb9f827 100644 --- a/mobile/test/drift/main/generated/schema_v1.dart +++ b/mobile/test/drift/main/generated/schema_v1.dart @@ -410,9 +410,15 @@ class RemoteAssetEntity extends Table late final GeneratedColumn deletedAt = GeneratedColumn( 'deleted_at', aliasedName, true, type: DriftSqlType.dateTime, requiredDuringInsert: false); + late final GeneratedColumn livePhotoVideoId = GeneratedColumn( + 'live_photo_video_id', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); late final GeneratedColumn visibility = GeneratedColumn( 'visibility', aliasedName, false, type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn stackId = GeneratedColumn( + 'stack_id', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); @override List get $columns => [ name, @@ -429,7 +435,9 @@ class RemoteAssetEntity extends Table localDateTime, thumbHash, deletedAt, - visibility + livePhotoVideoId, + visibility, + stackId ]; @override String get aliasedName => _alias ?? actualTableName; @@ -470,8 +478,12 @@ class RemoteAssetEntity extends Table .read(DriftSqlType.string, data['${effectivePrefix}thumb_hash']), deletedAt: attachedDatabase.typeMapping .read(DriftSqlType.dateTime, data['${effectivePrefix}deleted_at']), + livePhotoVideoId: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), visibility: attachedDatabase.typeMapping .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, + stackId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), ); } @@ -502,7 +514,9 @@ class RemoteAssetEntityData extends DataClass final DateTime? localDateTime; final String? thumbHash; final DateTime? deletedAt; + final String? livePhotoVideoId; final int visibility; + final String? stackId; const RemoteAssetEntityData( {required this.name, required this.type, @@ -518,7 +532,9 @@ class RemoteAssetEntityData extends DataClass this.localDateTime, this.thumbHash, this.deletedAt, - required this.visibility}); + this.livePhotoVideoId, + required this.visibility, + this.stackId}); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -548,7 +564,13 @@ class RemoteAssetEntityData extends DataClass if (!nullToAbsent || deletedAt != null) { map['deleted_at'] = Variable(deletedAt); } + if (!nullToAbsent || livePhotoVideoId != null) { + map['live_photo_video_id'] = Variable(livePhotoVideoId); + } map['visibility'] = Variable(visibility); + if (!nullToAbsent || stackId != null) { + map['stack_id'] = Variable(stackId); + } return map; } @@ -570,7 +592,9 @@ class RemoteAssetEntityData extends DataClass localDateTime: serializer.fromJson(json['localDateTime']), thumbHash: serializer.fromJson(json['thumbHash']), deletedAt: serializer.fromJson(json['deletedAt']), + livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), visibility: serializer.fromJson(json['visibility']), + stackId: serializer.fromJson(json['stackId']), ); } @override @@ -591,7 +615,9 @@ class RemoteAssetEntityData extends DataClass 'localDateTime': serializer.toJson(localDateTime), 'thumbHash': serializer.toJson(thumbHash), 'deletedAt': serializer.toJson(deletedAt), + 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), 'visibility': serializer.toJson(visibility), + 'stackId': serializer.toJson(stackId), }; } @@ -610,7 +636,9 @@ class RemoteAssetEntityData extends DataClass Value localDateTime = const Value.absent(), Value thumbHash = const Value.absent(), Value deletedAt = const Value.absent(), - int? visibility}) => + Value livePhotoVideoId = const Value.absent(), + int? visibility, + Value stackId = const Value.absent()}) => RemoteAssetEntityData( name: name ?? this.name, type: type ?? this.type, @@ -629,7 +657,11 @@ class RemoteAssetEntityData extends DataClass localDateTime.present ? localDateTime.value : this.localDateTime, thumbHash: thumbHash.present ? thumbHash.value : this.thumbHash, deletedAt: deletedAt.present ? deletedAt.value : this.deletedAt, + livePhotoVideoId: livePhotoVideoId.present + ? livePhotoVideoId.value + : this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( @@ -652,8 +684,12 @@ class RemoteAssetEntityData extends DataClass : this.localDateTime, thumbHash: data.thumbHash.present ? data.thumbHash.value : this.thumbHash, deletedAt: data.deletedAt.present ? data.deletedAt.value : this.deletedAt, + livePhotoVideoId: data.livePhotoVideoId.present + ? data.livePhotoVideoId.value + : this.livePhotoVideoId, visibility: data.visibility.present ? data.visibility.value : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -674,7 +710,9 @@ class RemoteAssetEntityData extends DataClass ..write('localDateTime: $localDateTime, ') ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') - ..write('visibility: $visibility') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } @@ -695,7 +733,9 @@ class RemoteAssetEntityData extends DataClass localDateTime, thumbHash, deletedAt, - visibility); + livePhotoVideoId, + visibility, + stackId); @override bool operator ==(Object other) => identical(this, other) || @@ -714,7 +754,9 @@ class RemoteAssetEntityData extends DataClass other.localDateTime == this.localDateTime && other.thumbHash == this.thumbHash && other.deletedAt == this.deletedAt && - other.visibility == this.visibility); + other.livePhotoVideoId == this.livePhotoVideoId && + other.visibility == this.visibility && + other.stackId == this.stackId); } class RemoteAssetEntityCompanion @@ -733,7 +775,9 @@ class RemoteAssetEntityCompanion final Value localDateTime; final Value thumbHash; final Value deletedAt; + final Value livePhotoVideoId; final Value visibility; + final Value stackId; const RemoteAssetEntityCompanion({ this.name = const Value.absent(), this.type = const Value.absent(), @@ -749,7 +793,9 @@ class RemoteAssetEntityCompanion this.localDateTime = const Value.absent(), this.thumbHash = const Value.absent(), this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), this.visibility = const Value.absent(), + this.stackId = const Value.absent(), }); RemoteAssetEntityCompanion.insert({ required String name, @@ -766,7 +812,9 @@ class RemoteAssetEntityCompanion this.localDateTime = const Value.absent(), this.thumbHash = const Value.absent(), this.deletedAt = const Value.absent(), + this.livePhotoVideoId = const Value.absent(), required int visibility, + this.stackId = const Value.absent(), }) : name = Value(name), type = Value(type), id = Value(id), @@ -788,7 +836,9 @@ class RemoteAssetEntityCompanion Expression? localDateTime, Expression? thumbHash, Expression? deletedAt, + Expression? livePhotoVideoId, Expression? visibility, + Expression? stackId, }) { return RawValuesInsertable({ if (name != null) 'name': name, @@ -805,7 +855,9 @@ class RemoteAssetEntityCompanion if (localDateTime != null) 'local_date_time': localDateTime, if (thumbHash != null) 'thumb_hash': thumbHash, if (deletedAt != null) 'deleted_at': deletedAt, + if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, }); } @@ -824,7 +876,9 @@ class RemoteAssetEntityCompanion Value? localDateTime, Value? thumbHash, Value? deletedAt, - Value? visibility}) { + Value? livePhotoVideoId, + Value? visibility, + Value? stackId}) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -840,7 +894,9 @@ class RemoteAssetEntityCompanion localDateTime: localDateTime ?? this.localDateTime, thumbHash: thumbHash ?? this.thumbHash, deletedAt: deletedAt ?? this.deletedAt, + livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, ); } @@ -889,9 +945,15 @@ class RemoteAssetEntityCompanion if (deletedAt.present) { map['deleted_at'] = Variable(deletedAt.value); } + if (livePhotoVideoId.present) { + map['live_photo_video_id'] = Variable(livePhotoVideoId.value); + } if (visibility.present) { map['visibility'] = Variable(visibility.value); } + if (stackId.present) { + map['stack_id'] = Variable(stackId.value); + } return map; } @@ -912,7 +974,9 @@ class RemoteAssetEntityCompanion ..write('localDateTime: $localDateTime, ') ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') - ..write('visibility: $visibility') + ..write('livePhotoVideoId: $livePhotoVideoId, ') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } @@ -1351,6 +1415,258 @@ class LocalAssetEntityCompanion extends UpdateCompanion { } } +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE')); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)')); + @override + List get $columns => + [id, createdAt, updatedAt, ownerId, primaryAssetId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}id'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + updatedAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + ownerId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData( + {required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith( + {String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId}) => + StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith( + {Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId}) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + class UserMetadataEntity extends Table with TableInfo { @override @@ -4329,263 +4645,12 @@ class MemoryAssetEntityCompanion } } -class StackEntity extends Table with TableInfo { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - StackEntity(this.attachedDatabase, [this._alias]); - late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); - @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'stack_entity'; - @override - Set get $primaryKey => {id}; - @override - StackEntityData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, - ); - } - - @override - StackEntity createAlias(String alias) { - return StackEntity(attachedDatabase, alias); - } - - @override - bool get withoutRowId => true; - @override - bool get isStrict => true; -} - -class StackEntityData extends DataClass implements Insertable { - final String id; - final DateTime createdAt; - final DateTime updatedAt; - final String ownerId; - final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['id'] = Variable(id); - map['created_at'] = Variable(createdAt); - map['updated_at'] = Variable(updatedAt); - map['owner_id'] = Variable(ownerId); - map['primary_asset_id'] = Variable(primaryAssetId); - return map; - } - - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return StackEntityData( - id: serializer.fromJson(json['id']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - ownerId: serializer.fromJson(json['ownerId']), - primaryAssetId: serializer.fromJson(json['primaryAssetId']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'ownerId': serializer.toJson(ownerId), - 'primaryAssetId': serializer.toJson(primaryAssetId), - }; - } - - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - StackEntityData copyWithCompanion(StackEntityCompanion data) { - return StackEntityData( - id: data.id.present ? data.id.value : this.id, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, - ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, - primaryAssetId: data.primaryAssetId.present - ? data.primaryAssetId.value - : this.primaryAssetId, - ); - } - - @override - String toString() { - return (StringBuffer('StackEntityData(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is StackEntityData && - other.id == this.id && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.ownerId == this.ownerId && - other.primaryAssetId == this.primaryAssetId); -} - -class StackEntityCompanion extends UpdateCompanion { - final Value id; - final Value createdAt; - final Value updatedAt; - final Value ownerId; - final Value primaryAssetId; - const StackEntityCompanion({ - this.id = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.ownerId = const Value.absent(), - this.primaryAssetId = const Value.absent(), - }); - StackEntityCompanion.insert({ - required String id, - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - required String ownerId, - required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); - static Insertable custom({ - Expression? id, - Expression? createdAt, - Expression? updatedAt, - Expression? ownerId, - Expression? primaryAssetId, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (ownerId != null) 'owner_id': ownerId, - if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, - }); - } - - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { - return StackEntityCompanion( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (ownerId.present) { - map['owner_id'] = Variable(ownerId.value); - } - if (primaryAssetId.present) { - map['primary_asset_id'] = Variable(primaryAssetId.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('StackEntityCompanion(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } -} - class DatabaseAtV1 extends GeneratedDatabase { DatabaseAtV1(QueryExecutor e) : super(e); late final UserEntity userEntity = UserEntity(this); late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); + late final StackEntity stackEntity = StackEntity(this); late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); late final Index uQRemoteAssetOwnerChecksum = Index( @@ -4606,7 +4671,6 @@ class DatabaseAtV1 extends GeneratedDatabase { RemoteAlbumUserEntity(this); late final MemoryEntity memoryEntity = MemoryEntity(this); late final MemoryAssetEntity memoryAssetEntity = MemoryAssetEntity(this); - late final StackEntity stackEntity = StackEntity(this); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -4615,6 +4679,7 @@ class DatabaseAtV1 extends GeneratedDatabase { userEntity, remoteAssetEntity, localAssetEntity, + stackEntity, idxLocalAssetChecksum, uQRemoteAssetOwnerChecksum, idxRemoteAssetChecksum, @@ -4627,8 +4692,7 @@ class DatabaseAtV1 extends GeneratedDatabase { remoteAlbumAssetEntity, remoteAlbumUserEntity, memoryEntity, - memoryAssetEntity, - stackEntity + memoryAssetEntity ]; @override int get schemaVersion => 1; diff --git a/mobile/test/drift/main/generated/schema_v2.dart b/mobile/test/drift/main/generated/schema_v2.dart index bdba8db557..8345cef906 100644 --- a/mobile/test/drift/main/generated/schema_v2.dart +++ b/mobile/test/drift/main/generated/schema_v2.dart @@ -416,6 +416,9 @@ class RemoteAssetEntity extends Table late final GeneratedColumn visibility = GeneratedColumn( 'visibility', aliasedName, false, type: DriftSqlType.int, requiredDuringInsert: true); + late final GeneratedColumn stackId = GeneratedColumn( + 'stack_id', aliasedName, true, + type: DriftSqlType.string, requiredDuringInsert: false); @override List get $columns => [ name, @@ -433,7 +436,8 @@ class RemoteAssetEntity extends Table thumbHash, deletedAt, livePhotoVideoId, - visibility + visibility, + stackId ]; @override String get aliasedName => _alias ?? actualTableName; @@ -478,6 +482,8 @@ class RemoteAssetEntity extends Table DriftSqlType.string, data['${effectivePrefix}live_photo_video_id']), visibility: attachedDatabase.typeMapping .read(DriftSqlType.int, data['${effectivePrefix}visibility'])!, + stackId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}stack_id']), ); } @@ -510,6 +516,7 @@ class RemoteAssetEntityData extends DataClass final DateTime? deletedAt; final String? livePhotoVideoId; final int visibility; + final String? stackId; const RemoteAssetEntityData( {required this.name, required this.type, @@ -526,7 +533,8 @@ class RemoteAssetEntityData extends DataClass this.thumbHash, this.deletedAt, this.livePhotoVideoId, - required this.visibility}); + required this.visibility, + this.stackId}); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -560,6 +568,9 @@ class RemoteAssetEntityData extends DataClass map['live_photo_video_id'] = Variable(livePhotoVideoId); } map['visibility'] = Variable(visibility); + if (!nullToAbsent || stackId != null) { + map['stack_id'] = Variable(stackId); + } return map; } @@ -583,6 +594,7 @@ class RemoteAssetEntityData extends DataClass deletedAt: serializer.fromJson(json['deletedAt']), livePhotoVideoId: serializer.fromJson(json['livePhotoVideoId']), visibility: serializer.fromJson(json['visibility']), + stackId: serializer.fromJson(json['stackId']), ); } @override @@ -605,6 +617,7 @@ class RemoteAssetEntityData extends DataClass 'deletedAt': serializer.toJson(deletedAt), 'livePhotoVideoId': serializer.toJson(livePhotoVideoId), 'visibility': serializer.toJson(visibility), + 'stackId': serializer.toJson(stackId), }; } @@ -624,7 +637,8 @@ class RemoteAssetEntityData extends DataClass Value thumbHash = const Value.absent(), Value deletedAt = const Value.absent(), Value livePhotoVideoId = const Value.absent(), - int? visibility}) => + int? visibility, + Value stackId = const Value.absent()}) => RemoteAssetEntityData( name: name ?? this.name, type: type ?? this.type, @@ -647,6 +661,7 @@ class RemoteAssetEntityData extends DataClass ? livePhotoVideoId.value : this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId.present ? stackId.value : this.stackId, ); RemoteAssetEntityData copyWithCompanion(RemoteAssetEntityCompanion data) { return RemoteAssetEntityData( @@ -674,6 +689,7 @@ class RemoteAssetEntityData extends DataClass : this.livePhotoVideoId, visibility: data.visibility.present ? data.visibility.value : this.visibility, + stackId: data.stackId.present ? data.stackId.value : this.stackId, ); } @@ -695,7 +711,8 @@ class RemoteAssetEntityData extends DataClass ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') - ..write('visibility: $visibility') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } @@ -717,7 +734,8 @@ class RemoteAssetEntityData extends DataClass thumbHash, deletedAt, livePhotoVideoId, - visibility); + visibility, + stackId); @override bool operator ==(Object other) => identical(this, other) || @@ -737,7 +755,8 @@ class RemoteAssetEntityData extends DataClass other.thumbHash == this.thumbHash && other.deletedAt == this.deletedAt && other.livePhotoVideoId == this.livePhotoVideoId && - other.visibility == this.visibility); + other.visibility == this.visibility && + other.stackId == this.stackId); } class RemoteAssetEntityCompanion @@ -758,6 +777,7 @@ class RemoteAssetEntityCompanion final Value deletedAt; final Value livePhotoVideoId; final Value visibility; + final Value stackId; const RemoteAssetEntityCompanion({ this.name = const Value.absent(), this.type = const Value.absent(), @@ -775,6 +795,7 @@ class RemoteAssetEntityCompanion this.deletedAt = const Value.absent(), this.livePhotoVideoId = const Value.absent(), this.visibility = const Value.absent(), + this.stackId = const Value.absent(), }); RemoteAssetEntityCompanion.insert({ required String name, @@ -793,6 +814,7 @@ class RemoteAssetEntityCompanion this.deletedAt = const Value.absent(), this.livePhotoVideoId = const Value.absent(), required int visibility, + this.stackId = const Value.absent(), }) : name = Value(name), type = Value(type), id = Value(id), @@ -816,6 +838,7 @@ class RemoteAssetEntityCompanion Expression? deletedAt, Expression? livePhotoVideoId, Expression? visibility, + Expression? stackId, }) { return RawValuesInsertable({ if (name != null) 'name': name, @@ -834,6 +857,7 @@ class RemoteAssetEntityCompanion if (deletedAt != null) 'deleted_at': deletedAt, if (livePhotoVideoId != null) 'live_photo_video_id': livePhotoVideoId, if (visibility != null) 'visibility': visibility, + if (stackId != null) 'stack_id': stackId, }); } @@ -853,7 +877,8 @@ class RemoteAssetEntityCompanion Value? thumbHash, Value? deletedAt, Value? livePhotoVideoId, - Value? visibility}) { + Value? visibility, + Value? stackId}) { return RemoteAssetEntityCompanion( name: name ?? this.name, type: type ?? this.type, @@ -871,6 +896,7 @@ class RemoteAssetEntityCompanion deletedAt: deletedAt ?? this.deletedAt, livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId, visibility: visibility ?? this.visibility, + stackId: stackId ?? this.stackId, ); } @@ -925,6 +951,9 @@ class RemoteAssetEntityCompanion if (visibility.present) { map['visibility'] = Variable(visibility.value); } + if (stackId.present) { + map['stack_id'] = Variable(stackId.value); + } return map; } @@ -946,7 +975,8 @@ class RemoteAssetEntityCompanion ..write('thumbHash: $thumbHash, ') ..write('deletedAt: $deletedAt, ') ..write('livePhotoVideoId: $livePhotoVideoId, ') - ..write('visibility: $visibility') + ..write('visibility: $visibility, ') + ..write('stackId: $stackId') ..write(')')) .toString(); } @@ -1385,6 +1415,258 @@ class LocalAssetEntityCompanion extends UpdateCompanion { } } +class StackEntity extends Table with TableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + StackEntity(this.attachedDatabase, [this._alias]); + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + late final GeneratedColumn createdAt = GeneratedColumn( + 'created_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + late final GeneratedColumn updatedAt = GeneratedColumn( + 'updated_at', aliasedName, false, + type: DriftSqlType.dateTime, + requiredDuringInsert: false, + defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES user_entity (id) ON DELETE CASCADE')); + late final GeneratedColumn primaryAssetId = GeneratedColumn( + 'primary_asset_id', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES remote_asset_entity (id)')); + @override + List get $columns => + [id, createdAt, updatedAt, ownerId, primaryAssetId]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'stack_entity'; + @override + Set get $primaryKey => {id}; + @override + StackEntityData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return StackEntityData( + id: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}id'])!, + createdAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, + updatedAt: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, + ownerId: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, + primaryAssetId: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, + ); + } + + @override + StackEntity createAlias(String alias) { + return StackEntity(attachedDatabase, alias); + } + + @override + bool get withoutRowId => true; + @override + bool get isStrict => true; +} + +class StackEntityData extends DataClass implements Insertable { + final String id; + final DateTime createdAt; + final DateTime updatedAt; + final String ownerId; + final String primaryAssetId; + const StackEntityData( + {required this.id, + required this.createdAt, + required this.updatedAt, + required this.ownerId, + required this.primaryAssetId}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['created_at'] = Variable(createdAt); + map['updated_at'] = Variable(updatedAt); + map['owner_id'] = Variable(ownerId); + map['primary_asset_id'] = Variable(primaryAssetId); + return map; + } + + factory StackEntityData.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return StackEntityData( + id: serializer.fromJson(json['id']), + createdAt: serializer.fromJson(json['createdAt']), + updatedAt: serializer.fromJson(json['updatedAt']), + ownerId: serializer.fromJson(json['ownerId']), + primaryAssetId: serializer.fromJson(json['primaryAssetId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'createdAt': serializer.toJson(createdAt), + 'updatedAt': serializer.toJson(updatedAt), + 'ownerId': serializer.toJson(ownerId), + 'primaryAssetId': serializer.toJson(primaryAssetId), + }; + } + + StackEntityData copyWith( + {String? id, + DateTime? createdAt, + DateTime? updatedAt, + String? ownerId, + String? primaryAssetId}) => + StackEntityData( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + StackEntityData copyWithCompanion(StackEntityCompanion data) { + return StackEntityData( + id: data.id.present ? data.id.value : this.id, + createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, + updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, + ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, + primaryAssetId: data.primaryAssetId.present + ? data.primaryAssetId.value + : this.primaryAssetId, + ); + } + + @override + String toString() { + return (StringBuffer('StackEntityData(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is StackEntityData && + other.id == this.id && + other.createdAt == this.createdAt && + other.updatedAt == this.updatedAt && + other.ownerId == this.ownerId && + other.primaryAssetId == this.primaryAssetId); +} + +class StackEntityCompanion extends UpdateCompanion { + final Value id; + final Value createdAt; + final Value updatedAt; + final Value ownerId; + final Value primaryAssetId; + const StackEntityCompanion({ + this.id = const Value.absent(), + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + this.ownerId = const Value.absent(), + this.primaryAssetId = const Value.absent(), + }); + StackEntityCompanion.insert({ + required String id, + this.createdAt = const Value.absent(), + this.updatedAt = const Value.absent(), + required String ownerId, + required String primaryAssetId, + }) : id = Value(id), + ownerId = Value(ownerId), + primaryAssetId = Value(primaryAssetId); + static Insertable custom({ + Expression? id, + Expression? createdAt, + Expression? updatedAt, + Expression? ownerId, + Expression? primaryAssetId, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (createdAt != null) 'created_at': createdAt, + if (updatedAt != null) 'updated_at': updatedAt, + if (ownerId != null) 'owner_id': ownerId, + if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, + }); + } + + StackEntityCompanion copyWith( + {Value? id, + Value? createdAt, + Value? updatedAt, + Value? ownerId, + Value? primaryAssetId}) { + return StackEntityCompanion( + id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ownerId: ownerId ?? this.ownerId, + primaryAssetId: primaryAssetId ?? this.primaryAssetId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (createdAt.present) { + map['created_at'] = Variable(createdAt.value); + } + if (updatedAt.present) { + map['updated_at'] = Variable(updatedAt.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + if (primaryAssetId.present) { + map['primary_asset_id'] = Variable(primaryAssetId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('StackEntityCompanion(') + ..write('id: $id, ') + ..write('createdAt: $createdAt, ') + ..write('updatedAt: $updatedAt, ') + ..write('ownerId: $ownerId, ') + ..write('primaryAssetId: $primaryAssetId') + ..write(')')) + .toString(); + } +} + class UserMetadataEntity extends Table with TableInfo { @override @@ -4363,263 +4645,12 @@ class MemoryAssetEntityCompanion } } -class StackEntity extends Table with TableInfo { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - StackEntity(this.attachedDatabase, [this._alias]); - late final GeneratedColumn id = GeneratedColumn( - 'id', aliasedName, false, - type: DriftSqlType.string, requiredDuringInsert: true); - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn updatedAt = GeneratedColumn( - 'updated_at', aliasedName, false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: const CustomExpression('CURRENT_TIMESTAMP')); - late final GeneratedColumn ownerId = GeneratedColumn( - 'owner_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES user_entity (id) ON DELETE CASCADE')); - late final GeneratedColumn primaryAssetId = GeneratedColumn( - 'primary_asset_id', aliasedName, false, - type: DriftSqlType.string, - requiredDuringInsert: true, - defaultConstraints: GeneratedColumn.constraintIsAlways( - 'REFERENCES remote_asset_entity (id)')); - @override - List get $columns => - [id, createdAt, updatedAt, ownerId, primaryAssetId]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'stack_entity'; - @override - Set get $primaryKey => {id}; - @override - StackEntityData map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return StackEntityData( - id: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}id'])!, - createdAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!, - updatedAt: attachedDatabase.typeMapping - .read(DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!, - ownerId: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}owner_id'])!, - primaryAssetId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}primary_asset_id'])!, - ); - } - - @override - StackEntity createAlias(String alias) { - return StackEntity(attachedDatabase, alias); - } - - @override - bool get withoutRowId => true; - @override - bool get isStrict => true; -} - -class StackEntityData extends DataClass implements Insertable { - final String id; - final DateTime createdAt; - final DateTime updatedAt; - final String ownerId; - final String primaryAssetId; - const StackEntityData( - {required this.id, - required this.createdAt, - required this.updatedAt, - required this.ownerId, - required this.primaryAssetId}); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['id'] = Variable(id); - map['created_at'] = Variable(createdAt); - map['updated_at'] = Variable(updatedAt); - map['owner_id'] = Variable(ownerId); - map['primary_asset_id'] = Variable(primaryAssetId); - return map; - } - - factory StackEntityData.fromJson(Map json, - {ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return StackEntityData( - id: serializer.fromJson(json['id']), - createdAt: serializer.fromJson(json['createdAt']), - updatedAt: serializer.fromJson(json['updatedAt']), - ownerId: serializer.fromJson(json['ownerId']), - primaryAssetId: serializer.fromJson(json['primaryAssetId']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'id': serializer.toJson(id), - 'createdAt': serializer.toJson(createdAt), - 'updatedAt': serializer.toJson(updatedAt), - 'ownerId': serializer.toJson(ownerId), - 'primaryAssetId': serializer.toJson(primaryAssetId), - }; - } - - StackEntityData copyWith( - {String? id, - DateTime? createdAt, - DateTime? updatedAt, - String? ownerId, - String? primaryAssetId}) => - StackEntityData( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - StackEntityData copyWithCompanion(StackEntityCompanion data) { - return StackEntityData( - id: data.id.present ? data.id.value : this.id, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt, - ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId, - primaryAssetId: data.primaryAssetId.present - ? data.primaryAssetId.value - : this.primaryAssetId, - ); - } - - @override - String toString() { - return (StringBuffer('StackEntityData(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(id, createdAt, updatedAt, ownerId, primaryAssetId); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is StackEntityData && - other.id == this.id && - other.createdAt == this.createdAt && - other.updatedAt == this.updatedAt && - other.ownerId == this.ownerId && - other.primaryAssetId == this.primaryAssetId); -} - -class StackEntityCompanion extends UpdateCompanion { - final Value id; - final Value createdAt; - final Value updatedAt; - final Value ownerId; - final Value primaryAssetId; - const StackEntityCompanion({ - this.id = const Value.absent(), - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - this.ownerId = const Value.absent(), - this.primaryAssetId = const Value.absent(), - }); - StackEntityCompanion.insert({ - required String id, - this.createdAt = const Value.absent(), - this.updatedAt = const Value.absent(), - required String ownerId, - required String primaryAssetId, - }) : id = Value(id), - ownerId = Value(ownerId), - primaryAssetId = Value(primaryAssetId); - static Insertable custom({ - Expression? id, - Expression? createdAt, - Expression? updatedAt, - Expression? ownerId, - Expression? primaryAssetId, - }) { - return RawValuesInsertable({ - if (id != null) 'id': id, - if (createdAt != null) 'created_at': createdAt, - if (updatedAt != null) 'updated_at': updatedAt, - if (ownerId != null) 'owner_id': ownerId, - if (primaryAssetId != null) 'primary_asset_id': primaryAssetId, - }); - } - - StackEntityCompanion copyWith( - {Value? id, - Value? createdAt, - Value? updatedAt, - Value? ownerId, - Value? primaryAssetId}) { - return StackEntityCompanion( - id: id ?? this.id, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt, - ownerId: ownerId ?? this.ownerId, - primaryAssetId: primaryAssetId ?? this.primaryAssetId, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (id.present) { - map['id'] = Variable(id.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (updatedAt.present) { - map['updated_at'] = Variable(updatedAt.value); - } - if (ownerId.present) { - map['owner_id'] = Variable(ownerId.value); - } - if (primaryAssetId.present) { - map['primary_asset_id'] = Variable(primaryAssetId.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('StackEntityCompanion(') - ..write('id: $id, ') - ..write('createdAt: $createdAt, ') - ..write('updatedAt: $updatedAt, ') - ..write('ownerId: $ownerId, ') - ..write('primaryAssetId: $primaryAssetId') - ..write(')')) - .toString(); - } -} - class DatabaseAtV2 extends GeneratedDatabase { DatabaseAtV2(QueryExecutor e) : super(e); late final UserEntity userEntity = UserEntity(this); late final RemoteAssetEntity remoteAssetEntity = RemoteAssetEntity(this); late final LocalAssetEntity localAssetEntity = LocalAssetEntity(this); + late final StackEntity stackEntity = StackEntity(this); late final Index idxLocalAssetChecksum = Index('idx_local_asset_checksum', 'CREATE INDEX idx_local_asset_checksum ON local_asset_entity (checksum)'); late final Index uQRemoteAssetOwnerChecksum = Index( @@ -4640,7 +4671,6 @@ class DatabaseAtV2 extends GeneratedDatabase { RemoteAlbumUserEntity(this); late final MemoryEntity memoryEntity = MemoryEntity(this); late final MemoryAssetEntity memoryAssetEntity = MemoryAssetEntity(this); - late final StackEntity stackEntity = StackEntity(this); @override Iterable> get allTables => allSchemaEntities.whereType>(); @@ -4649,6 +4679,7 @@ class DatabaseAtV2 extends GeneratedDatabase { userEntity, remoteAssetEntity, localAssetEntity, + stackEntity, idxLocalAssetChecksum, uQRemoteAssetOwnerChecksum, idxRemoteAssetChecksum, @@ -4661,8 +4692,7 @@ class DatabaseAtV2 extends GeneratedDatabase { remoteAlbumAssetEntity, remoteAlbumUserEntity, memoryEntity, - memoryAssetEntity, - stackEntity + memoryAssetEntity ]; @override int get schemaVersion => 2;