feat(mobile): add three-state field serialization - #27231
Conversation
f6dea8b to
2503e74
Compare
2503e74 to
dbec691
Compare
This comment was marked as outdated.
This comment was marked as outdated.
dbec691 to
49b30ea
Compare
3753a3e to
8faa495
Compare
|
📱 Android release APK (universal) — Download: https://github.com/immich-app/immich/actions/runs/26042656731/artifacts/7062131338 Installs as a separate app (applicationId |
8faa495 to
b25413c
Compare
b25413c to
182de98
Compare
jrasm91
left a comment
There was a problem hiding this comment.
Code LGTM. Will need more testing though.
|
Deploying preview environment to https://pr-27231.preview.internal.immich.build/ |
tested this against current main server. yielded some unrelated "silent" bugs that were hidden due to our patching efforts in the dart client. apart from that the mobile app worked fine with the above changes. Imo good to merge now! (some patches can be dropped once upstream 7.23.0 is released, got it on my list) . Below I list all "unrelated" bugs found so far: |
182de98 to
0b39f43
Compare
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794) * fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743) micromatch parses bare `(user)` as an empty regex capture group, so ownership globs like `web/src/routes/(user)/spaces/**` silently matched nothing in coverage.ts (both the ignore filter and the glob classifier). Port the literal-parens escaping the S20 manifest guard already uses. * fix(server): make rapid re-trims of the same video race-free (#743) Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg` (one job's cleanup unlinked the frame the other was reading -> 'Input file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while the previous job could still be probing it. - serialize trims per asset id (AsyncLock, in-process) - unique per-invocation temp frame path (covers cross-process overlap) - trim to a temp file and atomically rename into place * fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743) LibraryAssetSync streamed the raw asset.isFavorite to every library member. Apply the same per-row ownership mask SharedSpaceAssetSync / AlbumAssetSync use (owner keeps the flag, everyone else sees false) on both the backfill and upsert paths. * fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743) - asset_offline_description was the #672 bug shape again: overridden at the TOP LEVEL with the admin-block text, clobbering the user-facing string while admin.asset_offline_description kept leaking 'Immich'. Both nesting levels now carry their own branded text. - add overrides for import_option_skip_duplicates, my_immich_title, my_immich_description (the my.immich.app redirect service keeps its domain name). - verify-branding.sh and test-i18n-branding.sh only checked keys that HAVE overrides, so a leaking key with no override passed silently — both now scan every string value in the branded en.json. * fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743) The patch that types nullable-item arrays as List<T?> was orphaned: generate-dart-sdk.sh stopped applying it after the upstream three-state DTO template rework (immich-app#27231) rewrote the same template regions, so TimeBucketAssetResponseDto declared its 8 nullable-item array fields as non-nullable and a null city/thumbhash/duration item threw at decode time instead of surfacing in the type system. - re-author the hunks against the current (post-immich-app#27231) template, covering required, x-is-optional, and plain-optional declarations; the rebuild only kicks in when items.isNullable so no other model regenerates differently - re-insert the patch application into generate-dart-sdk.sh (after native_class.mustache.patch, which its hunks are authored against) - drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch) — the template now produces the same declaration - add a preflight guard: the script must keep applying the patch, and every nullable-item array in the spec must be List<T?> in the committed generated model (this is the guard that would have caught the orphaning) The old patch's third hunk (implicit-optional number parsing) is obsolete: the x-is-optional pipeline now handles absent/null numbers. Verified: full mobile test suite (2520 tests) + dart analyze --fatal-infos green on the regenerated SDK. * chore(server): satisfy require-await in the trim-serialization test (#743)
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794) * fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743) micromatch parses bare `(user)` as an empty regex capture group, so ownership globs like `web/src/routes/(user)/spaces/**` silently matched nothing in coverage.ts (both the ignore filter and the glob classifier). Port the literal-parens escaping the S20 manifest guard already uses. * fix(server): make rapid re-trims of the same video race-free (#743) Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg` (one job's cleanup unlinked the frame the other was reading -> 'Input file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while the previous job could still be probing it. - serialize trims per asset id (AsyncLock, in-process) - unique per-invocation temp frame path (covers cross-process overlap) - trim to a temp file and atomically rename into place * fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743) LibraryAssetSync streamed the raw asset.isFavorite to every library member. Apply the same per-row ownership mask SharedSpaceAssetSync / AlbumAssetSync use (owner keeps the flag, everyone else sees false) on both the backfill and upsert paths. * fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743) - asset_offline_description was the #672 bug shape again: overridden at the TOP LEVEL with the admin-block text, clobbering the user-facing string while admin.asset_offline_description kept leaking 'Immich'. Both nesting levels now carry their own branded text. - add overrides for import_option_skip_duplicates, my_immich_title, my_immich_description (the my.immich.app redirect service keeps its domain name). - verify-branding.sh and test-i18n-branding.sh only checked keys that HAVE overrides, so a leaking key with no override passed silently — both now scan every string value in the branded en.json. * fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743) The patch that types nullable-item arrays as List<T?> was orphaned: generate-dart-sdk.sh stopped applying it after the upstream three-state DTO template rework (immich-app#27231) rewrote the same template regions, so TimeBucketAssetResponseDto declared its 8 nullable-item array fields as non-nullable and a null city/thumbhash/duration item threw at decode time instead of surfacing in the type system. - re-author the hunks against the current (post-immich-app#27231) template, covering required, x-is-optional, and plain-optional declarations; the rebuild only kicks in when items.isNullable so no other model regenerates differently - re-insert the patch application into generate-dart-sdk.sh (after native_class.mustache.patch, which its hunks are authored against) - drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch) — the template now produces the same declaration - add a preflight guard: the script must keep applying the patch, and every nullable-item array in the spec must be List<T?> in the committed generated model (this is the guard that would have caught the orphaning) The old patch's third hunk (implicit-optional number parsing) is obsolete: the x-is-optional pipeline now handles absent/null numbers. Verified: full mobile test suite (2520 tests) + dart analyze --fatal-infos green on the regenerated SDK. * chore(server): satisfy require-await in the trim-serialization test (#743)
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794) * fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743) micromatch parses bare `(user)` as an empty regex capture group, so ownership globs like `web/src/routes/(user)/spaces/**` silently matched nothing in coverage.ts (both the ignore filter and the glob classifier). Port the literal-parens escaping the S20 manifest guard already uses. * fix(server): make rapid re-trims of the same video race-free (#743) Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg` (one job's cleanup unlinked the frame the other was reading -> 'Input file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while the previous job could still be probing it. - serialize trims per asset id (AsyncLock, in-process) - unique per-invocation temp frame path (covers cross-process overlap) - trim to a temp file and atomically rename into place * fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743) LibraryAssetSync streamed the raw asset.isFavorite to every library member. Apply the same per-row ownership mask SharedSpaceAssetSync / AlbumAssetSync use (owner keeps the flag, everyone else sees false) on both the backfill and upsert paths. * fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743) - asset_offline_description was the #672 bug shape again: overridden at the TOP LEVEL with the admin-block text, clobbering the user-facing string while admin.asset_offline_description kept leaking 'Immich'. Both nesting levels now carry their own branded text. - add overrides for import_option_skip_duplicates, my_immich_title, my_immich_description (the my.immich.app redirect service keeps its domain name). - verify-branding.sh and test-i18n-branding.sh only checked keys that HAVE overrides, so a leaking key with no override passed silently — both now scan every string value in the branded en.json. * fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743) The patch that types nullable-item arrays as List<T?> was orphaned: generate-dart-sdk.sh stopped applying it after the upstream three-state DTO template rework (immich-app#27231) rewrote the same template regions, so TimeBucketAssetResponseDto declared its 8 nullable-item array fields as non-nullable and a null city/thumbhash/duration item threw at decode time instead of surfacing in the type system. - re-author the hunks against the current (post-immich-app#27231) template, covering required, x-is-optional, and plain-optional declarations; the rebuild only kicks in when items.isNullable so no other model regenerates differently - re-insert the patch application into generate-dart-sdk.sh (after native_class.mustache.patch, which its hunks are authored against) - drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch) — the template now produces the same declaration - add a preflight guard: the script must keep applying the patch, and every nullable-item array in the spec must be List<T?> in the committed generated model (this is the guard that would have caught the orphaning) The old patch's third hunk (implicit-optional number parsing) is obsolete: the x-is-optional pipeline now handles absent/null numbers. Verified: full mobile test suite (2520 tests) + dart analyze --fatal-infos green on the regenerated SDK. * chore(server): satisfy require-await in the trim-serialization test (#743)
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794) * fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743) micromatch parses bare `(user)` as an empty regex capture group, so ownership globs like `web/src/routes/(user)/spaces/**` silently matched nothing in coverage.ts (both the ignore filter and the glob classifier). Port the literal-parens escaping the S20 manifest guard already uses. * fix(server): make rapid re-trims of the same video race-free (#743) Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg` (one job's cleanup unlinked the frame the other was reading -> 'Input file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while the previous job could still be probing it. - serialize trims per asset id (AsyncLock, in-process) - unique per-invocation temp frame path (covers cross-process overlap) - trim to a temp file and atomically rename into place * fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743) LibraryAssetSync streamed the raw asset.isFavorite to every library member. Apply the same per-row ownership mask SharedSpaceAssetSync / AlbumAssetSync use (owner keeps the flag, everyone else sees false) on both the backfill and upsert paths. * fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743) - asset_offline_description was the #672 bug shape again: overridden at the TOP LEVEL with the admin-block text, clobbering the user-facing string while admin.asset_offline_description kept leaking 'Immich'. Both nesting levels now carry their own branded text. - add overrides for import_option_skip_duplicates, my_immich_title, my_immich_description (the my.immich.app redirect service keeps its domain name). - verify-branding.sh and test-i18n-branding.sh only checked keys that HAVE overrides, so a leaking key with no override passed silently — both now scan every string value in the branded en.json. * fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743) The patch that types nullable-item arrays as List<T?> was orphaned: generate-dart-sdk.sh stopped applying it after the upstream three-state DTO template rework (immich-app#27231) rewrote the same template regions, so TimeBucketAssetResponseDto declared its 8 nullable-item array fields as non-nullable and a null city/thumbhash/duration item threw at decode time instead of surfacing in the type system. - re-author the hunks against the current (post-immich-app#27231) template, covering required, x-is-optional, and plain-optional declarations; the rebuild only kicks in when items.isNullable so no other model regenerates differently - re-insert the patch application into generate-dart-sdk.sh (after native_class.mustache.patch, which its hunks are authored against) - drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch) — the template now produces the same declaration - add a preflight guard: the script must keep applying the patch, and every nullable-item array in the spec must be List<T?> in the committed generated model (this is the guard that would have caught the orphaning) The old patch's third hunk (implicit-optional number parsing) is obsolete: the x-is-optional pipeline now handles absent/null numbers. Verified: full mobile test suite (2520 tests) + dart analyze --fatal-infos green on the regenerated SDK. * chore(server): satisfy require-await in the trim-serialization test (#743)
…ich-app#27231) Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all mobile DTO fields three-state Optional<T?>. Changes: - Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0: upstream's three-state + array/complex-Optional fromJson handling + the fork's #584 date birth-fix. - Regenerate the mobile OpenAPI dart client. - Adapt 8 fork mobile files (space_card, shared_space_api.repository, drift_library.page, + test fixtures/specs) to read/write Optional fields. dart analyze lib+test clean; flutter tests pass.
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization, but the openapi-generator v7.22.0 useOptional branch reintroduced it for three-state fields when batch 183 adopted upstream immich-app#27231 — shifting birthdays by a day for users west/east of UTC. Extend the native_class.mustache patch to the x-is-optional date branch and regenerate the affected DTOs. CI never caught it because runners are UTC; the fork's person_update_dto_test only fails in non-UTC timezones.
Upgrade the openapi-generator to the latest version: v7.22.0, which enables the Dart client to distinguish between:
The PR looks big, that's mostly due to the client generation (2nd commit). The actual changes are small. Mobile call sites have been migrated by resolving errors reported by
mise //mobile:analyze:dartFor additional context read the outline doc.