diff --git a/.gitattributes b/.gitattributes
index e3fb061bbc..e1225939b1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -6,6 +6,12 @@ mobile/openapi/**/*.dart linguist-generated=true
mobile/lib/**/*.g.dart -diff -merge
mobile/lib/**/*.g.dart linguist-generated=true
+mobile/android/**/*.g.kt -diff -merge
+mobile/android/**/*.g.kt linguist-generated=true
+
+mobile/ios/**/*.g.swift -diff -merge
+mobile/ios/**/*.g.swift linguist-generated=true
+
mobile/lib/**/*.drift.dart -diff -merge
mobile/lib/**/*.drift.dart linguist-generated=true
diff --git a/.github/.nvmrc b/.github/.nvmrc
index 8e35034890..5bf4400f22 100644
--- a/.github/.nvmrc
+++ b/.github/.nvmrc
@@ -1 +1 @@
-24.14.1
+24.15.0
diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml
index c2a3918cfe..72e8b10aeb 100644
--- a/.github/workflows/build-mobile.yml
+++ b/.github/workflows/build-mobile.yml
@@ -103,7 +103,7 @@ jobs:
- name: Restore Gradle Cache
id: cache-gradle-restore
- uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.gradle/caches
@@ -160,7 +160,7 @@ jobs:
- name: Save Gradle Cache
id: cache-gradle-save
- uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
+ uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
if: github.ref == 'refs/heads/main'
with:
path: |
@@ -210,7 +210,7 @@ jobs:
working-directory: ./mobile
- name: Setup Ruby
- uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
+ uses: ruby/setup-ruby@7372622e62b60b3cb750dcd2b9e32c247ffec26a # v1.302.0
with:
ruby-version: '3.3'
bundler-cache: true
diff --git a/.github/workflows/check-openapi.yml b/.github/workflows/check-openapi.yml
index 3b3eb774cb..f2d03f7400 100644
--- a/.github/workflows/check-openapi.yml
+++ b/.github/workflows/check-openapi.yml
@@ -24,7 +24,7 @@ jobs:
persist-credentials: false
- name: Check for breaking API changes
- uses: oasdiff/oasdiff-action/breaking@e6faebce24cf20ac38653d0d2c7f4aa80aaafc79 # v0.0.38
+ uses: oasdiff/oasdiff-action/breaking@f8cb9308b42121e793f835bd14c0b8090420430c # v0.0.39
with:
base: https://raw.githubusercontent.com/${{ github.repository }}/main/open-api/immich-openapi-specs.json
revision: open-api/immich-openapi-specs.json
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 2378b032b6..f2d99ae1e8 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -57,7 +57,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
+ uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -70,7 +70,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
+ uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -83,6 +83,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
+ uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
category: '/language:${{matrix.language}}'
diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml
index 8aa063e1bb..57ea2d41d4 100644
--- a/.github/workflows/docs-deploy.yml
+++ b/.github/workflows/docs-deploy.yml
@@ -211,7 +211,7 @@ jobs:
run: 'mise run //deployment:tf apply'
- name: Comment
- uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3.2.0
+ uses: actions-cool/maintain-one-comment@909842216bc8e8658364c572ec52100f4c2cc50a # v3.3.0
if: ${{ steps.parameters.outputs.event == 'pr' }}
with:
token: ${{ steps.token.outputs.token }}
diff --git a/.github/workflows/docs-destroy.yml b/.github/workflows/docs-destroy.yml
index bb24a017fe..0e9c37a66c 100644
--- a/.github/workflows/docs-destroy.yml
+++ b/.github/workflows/docs-destroy.yml
@@ -42,7 +42,7 @@ jobs:
run: 'mise run //deployment:tf destroy -- -refresh=false'
- name: Comment
- uses: actions-cool/maintain-one-comment@4b2dbf086015f892dcb5e8c1106f5fccd6c1476b # v3.2.0
+ uses: actions-cool/maintain-one-comment@909842216bc8e8658364c572ec52100f4c2cc50a # v3.3.0
with:
token: ${{ steps.token.outputs.token }}
number: ${{ github.event.number }}
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
index 5731c06372..2aa028b22e 100644
--- a/.github/workflows/prepare-release.yml
+++ b/.github/workflows/prepare-release.yml
@@ -142,7 +142,7 @@ jobs:
github-token: ${{ steps.generate-token.outputs.token }}
- name: Create draft release
- uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
+ uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
draft: true
tag_name: ${{ needs.bump_version.outputs.version }}
diff --git a/.gitmodules b/.gitmodules
index d417dc5ba8..50a43933a9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "mobile/.isar"]
- path = mobile/.isar
- url = https://github.com/isar/isar
[submodule "e2e/test-assets"]
path = e2e/test-assets
url = https://github.com/immich-app/test-assets
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 496e7539e1..eeb80649ba 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -13,10 +13,6 @@
"editor.wordBasedSuggestions": "off"
},
"[javascript]": {
- "editor.codeActionsOnSave": {
- "source.organizeImports": "explicit",
- "source.removeUnusedImports": "explicit"
- },
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
@@ -29,18 +25,10 @@
"editor.formatOnSave": true
},
"[svelte]": {
- "editor.codeActionsOnSave": {
- "source.organizeImports": "explicit",
- "source.removeUnusedImports": "explicit"
- },
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.formatOnSave": true
},
"[typescript]": {
- "editor.codeActionsOnSave": {
- "source.organizeImports": "explicit",
- "source.removeUnusedImports": "explicit"
- },
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
diff --git a/cli/.nvmrc b/cli/.nvmrc
index 8e35034890..5bf4400f22 100644
--- a/cli/.nvmrc
+++ b/cli/.nvmrc
@@ -1 +1 @@
-24.14.1
+24.15.0
diff --git a/cli/package.json b/cli/package.json
index 108e65f945..7b42f77ff1 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -68,6 +68,6 @@
"micromatch": "^4.0.8"
},
"volta": {
- "node": "24.14.1"
+ "node": "24.15.0"
}
}
diff --git a/deployment/mise.toml b/deployment/mise.toml
index 8a01695fa7..61a50bb666 100644
--- a/deployment/mise.toml
+++ b/deployment/mise.toml
@@ -1,6 +1,6 @@
[tools]
-terragrunt = "1.0.0"
-opentofu = "1.11.5"
+terragrunt = "1.0.2"
+opentofu = "1.11.6"
[tasks."tg:fmt"]
run = "terragrunt hclfmt"
diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml
index 700f68ff19..25751879f3 100644
--- a/docker/docker-compose.prod.yml
+++ b/docker/docker-compose.prod.yml
@@ -85,7 +85,7 @@ services:
container_name: immich_prometheus
ports:
- 9090:9090
- image: prom/prometheus@sha256:dda13e28bf95a5e5ca5b8ed56852006094c1c8e8871d9c9dbeed30aa6e55271f
+ image: prom/prometheus@sha256:e4254400b85610324913f0dc4acf92603d9984e7519414c5a12811aa6146acc3
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
diff --git a/docs/.nvmrc b/docs/.nvmrc
index 8e35034890..5bf4400f22 100644
--- a/docs/.nvmrc
+++ b/docs/.nvmrc
@@ -1 +1 @@
-24.14.1
+24.15.0
diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md
index ae605f8462..debbad7575 100644
--- a/docs/docs/administration/backup-and-restore.md
+++ b/docs/docs/administration/backup-and-restore.md
@@ -210,7 +210,7 @@ The provided restore process ensures your database is never in a broken state by
## Filesystem
-Immich stores two types of content in the filesystem: (a) original, unmodified assets (photos and videos), and (b) generated content. We recommend backing up the entire contents of `UPLOAD_LOCATION`, but only the original content is critical, which is stored in the following folders:
+Immich does not handle filesystem backups for you. You have to arrange these yourself! Immich stores two types of content in the filesystem: (a) original, unmodified assets (photos and videos), and (b) generated content. We recommend backing up the entire contents of `UPLOAD_LOCATION`, but only the original content is critical, which is stored in the following folders:
1. `UPLOAD_LOCATION/library`
2. `UPLOAD_LOCATION/upload`
diff --git a/docs/docs/administration/oauth.md b/docs/docs/administration/oauth.md
index 3b1e8c729d..fea73684fd 100644
--- a/docs/docs/administration/oauth.md
+++ b/docs/docs/administration/oauth.md
@@ -50,6 +50,10 @@ Before enabling OAuth in Immich, a new client application needs to be configured
- `https://immich.example.com/auth/login`
- `https://immich.example.com/user-settings`
+3. Configure Backchannel logout URL
+
+ If the authentication server supports it, the **Backchannel logout URL** can be specified, and it is of the form: `http://DOMAIN:PORT/api/oauth/backchannel-logout`.
+
## Enable OAuth
Once you have a new OAuth client application configured, Immich can be configured using the Administration Settings page, available on the web (Administration -> Settings).
@@ -63,6 +67,8 @@ Once you have a new OAuth client application configured, Immich can be configure
| `scope` | string | openid email profile | Full list of scopes to send with the request (space delimited) |
| `id_token_signed_response_alg` | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
| `userinfo_signed_response_alg` | string | none | The algorithm used to sign the userinfo response (examples: RS256, HS256) |
+| `prompt` | string | (empty) | Prompt parameter for authorization url (examples: select_account, login, consent) |
+| `end_session_endpoint` | URL | (empty) | Http(s) alternative end session endpoint (logout URI) |
| Request timeout | string | 30,000 (30 seconds) | Number of milliseconds to wait for http requests to complete before giving up |
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**¹** |
| Role Claim | string | immich_role | Claim mapping for the user's role. (should return "user" or "admin")**¹** |
@@ -181,6 +187,7 @@ Configuration of OAuth in Immich System Settings
| Scope | openid email profile immich_scope |
| ID Token Signed Response Algorithm | RS256 |
| Userinfo Signed Response Algorithm | RS256 |
+| End Session Endpoint | https://auth.example.com/logout?rd=https://immich.example.com/ |
| Storage Label Claim | uid |
| Storage Quota Claim | immich_quota |
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
diff --git a/docs/docs/features/supported-formats.md b/docs/docs/features/supported-formats.md
index 86ac264cc3..917950dd2a 100644
--- a/docs/docs/features/supported-formats.md
+++ b/docs/docs/features/supported-formats.md
@@ -18,6 +18,7 @@ For the full list, refer to the [Immich source code](https://github.com/immich-a
| `JPEG 2000` | `.jp2` | :white_check_mark: | |
| `JPEG` | `.jpeg` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `JPEG XL` | `.jxl` | :white_check_mark: | |
+| `MPO` | `.mpo` | :white_check_mark: | Multi-Picture |
| `PNG` | `.png` | :white_check_mark: | |
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |
| `RAW` | `.raw` | :white_check_mark: | |
diff --git a/docs/docs/install/config-file.md b/docs/docs/install/config-file.md
index 3355750603..4754497d90 100644
--- a/docs/docs/install/config-file.md
+++ b/docs/docs/install/config-file.md
@@ -193,6 +193,7 @@ The default configuration looks like this:
"defaultStorageQuota": null,
"enabled": false,
"issuerUrl": "",
+ "endSessionEndpoint": "",
"mobileOverrideEnabled": false,
"mobileRedirectUri": "",
"profileSigningAlgorithm": "none",
diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md
index 41068dee97..b29c233153 100644
--- a/docs/docs/install/environment-variables.md
+++ b/docs/docs/install/environment-variables.md
@@ -37,7 +37,7 @@ These environment variables are used by the `docker-compose.yml` file and do **N
| `IMMICH_LOG_FORMAT` | Log output format (`console`, `json`) | `console` | server | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**\*2⚠️ | `/data` | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
-| `IMMICH_HELMET_FILE` | Path to a json file with [helmet](https://www.npmjs.com/package/helmet) options. Set to `false` to disable. Set to `true` to use `server/helmet.json`. | `false` | server | api, microservices |
+| `IMMICH_HELMET_FILE` | Path to a json file with [helmet](https://www.npmjs.com/package/helmet) options. Set to `false` to disable. Set to `true` to use `server/helmet.json`. | `false` | server | api |
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
diff --git a/docs/package.json b/docs/package.json
index f976791279..d469d1ffef 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -17,10 +17,10 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
- "@docusaurus/core": "~3.9.0",
- "@docusaurus/preset-classic": "~3.9.0",
- "@docusaurus/theme-common": "~3.9.0",
- "@docusaurus/theme-mermaid": "~3.9.0",
+ "@docusaurus/core": "~3.10.0",
+ "@docusaurus/preset-classic": "~3.10.0",
+ "@docusaurus/theme-common": "~3.10.0",
+ "@docusaurus/theme-mermaid": "~3.10.0",
"@mdi/js": "^7.3.67",
"@mdi/react": "^1.6.1",
"@mdx-js/react": "^3.0.0",
@@ -36,9 +36,9 @@
"url": "^0.11.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "~3.9.0",
+ "@docusaurus/module-type-aliases": "~3.10.0",
"@docusaurus/tsconfig": "^3.10.0",
- "@docusaurus/types": "^3.7.0",
+ "@docusaurus/types": "^3.10.0",
"prettier": "^3.7.4",
"typescript": "^6.0.0"
},
@@ -58,6 +58,6 @@
"node": ">=20"
},
"volta": {
- "node": "24.14.1"
+ "node": "24.15.0"
}
}
diff --git a/e2e-auth-server/auth-server.ts b/e2e-auth-server/auth-server.ts
index bcfeca1e1c..15aaa71c1c 100644
--- a/e2e-auth-server/auth-server.ts
+++ b/e2e-auth-server/auth-server.ts
@@ -1,5 +1,12 @@
-import { exportJWK, generateKeyPair } from 'jose';
+import {
+ calculateJwkThumbprint,
+ exportJWK,
+ importPKCS8,
+ importSPKI,
+ SignJWT,
+} from 'jose';
import Provider from 'oidc-provider';
+import { PRIVATE_KEY_PEM, PUBLIC_KEY_PEM } from './test-keys';
export enum OAuthClient {
DEFAULT = 'client-default',
@@ -44,6 +51,29 @@ const claims = [
},
];
+const privateKey = await importPKCS8(PRIVATE_KEY_PEM, 'RS256', {
+ extractable: true,
+});
+const publicKey = await importSPKI(PUBLIC_KEY_PEM, 'RS256', {
+ extractable: true,
+});
+const kid = await calculateJwkThumbprint(await exportJWK(publicKey));
+
+export async function generateLogoutToken(iss: string, sub: string) {
+ return await new SignJWT({
+ iss: iss,
+ aud: OAuthClient.DEFAULT,
+ iat: Math.floor(Date.now() / 1000),
+ jti: crypto.randomUUID(),
+ sub: sub,
+ events: {
+ 'http://schemas.openid.net/event/backchannel-logout': {},
+ },
+ })
+ .setProtectedHeader({ alg: 'RS256', typ: 'logout+jwt', kid: kid })
+ .sign(privateKey);
+}
+
const withDefaultClaims = (sub: string) => ({
sub,
email: `${sub}@immich.app`,
@@ -66,10 +96,6 @@ const getClaims = (sub: string, use?: string) => {
};
const setup = async () => {
- const { privateKey, publicKey } = await generateKeyPair('RS256', {
- extractable: true,
- });
-
const redirectUris = [
'http://127.0.0.1:2285/auth/login',
'https://photos.immich.app/oauth/mobile-redirect',
diff --git a/e2e-auth-server/test-keys.ts b/e2e-auth-server/test-keys.ts
new file mode 100644
index 0000000000..a37e822029
--- /dev/null
+++ b/e2e-auth-server/test-keys.ts
@@ -0,0 +1,38 @@
+export const PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCVj5C7hzN3E2HO
+TcJ+DN/e2NSTQFj4rPylz4J8xjm8Es7l0k2kK5EEGvUNVGZbw7s055c+6kwP9eqg
+B5XFE7+26Fcq1sou6Tbm310kU4dnMW5l2CgwrhaGyb1pNysao0AMLT60dFYqtUwn
+ha9ceCsa+ZU1JrknVf3rONtppBvhWoI7CO9XX1keVQ0unHPzCWUjpXTzC8OGEbmB
+2w7ZIUf8OfJkd5RZ4OtIpML71W9n13aDxT50x2/EW/pFLFtQ/oaleOKHpvlRXDRX
+W86G4moUJym3gHMXMUj2aOcFG2UJnpLruKz3i5qZwYiTRlBP6O9EIQNCVtYxchuN
+V1CCcBU1AgMBAAECggEAJLfXMu8Nx89ynPVyyUMMaFfoEpHC9iR0L5obQVpiPMYK
+VRqVVLecdftPS9s7eQ58BNBRzdC0ZVu841aRYs3HLNbsZZhPkYZQpAxU//Dg5okY
+fzj7Hv5yidt4HN9+Pd8z/3lRMnj4WapifLaBt8xJ2ujJBMBRxzJBsXDnT0+Kx7+y
+bYDeuVfyUTEikaK3QZTbuRF3D3eiuN16GG+hv8UqTF2eYbPxdiLjYpTSHa4mH88C
+qfJz2Xt4SEzmyeo3G+MO17wDFOwtEe8ojlJfULHnHJSFdUwTfYIFM1bg5/fJ9MOS
+/fO3TSG+wkQqjQa6eoGssAzP87fL2XNLzlDtGY/7uQKBgQDHuJHOtf1EjOvNYiP7
+EN+8QGs41ghzt9CQRQxWbHpusR3IW3P83KMXwYmrlG70oOUXBRGSB/ESXUofXc5W
+pu5+Y55S44aUnu/a9yOBttYW0dtHZSL0zFT+PlVASwUzFZ2zcH1KXlUkSpfL5OAD
+PyDDTnBZ2AWh45fRO9wLo6PPuQKBgQC/tI03RqU3mOjqukKbquYeIpXHfRU5Z0DM
+u9ru1THYEl6fmkMXycxo/mvW3awyFuyKy/VodqIgKnFgumEqCHZh6OAMm/LC7TfA
+l9tjFSs/MyOqQVD4kbX+z6Oq4c4GccDoXfsQ3gzECoBapegi/F+6/25y+/C8ghXb
+J/Jg1GQXXQKBgQDFgWbfzuVZZyrBfu4qGLPJDMN7/114YizknwPma3xf/tN/EcGQ
+K/k1QvWMMkvPq1UiAKcxjJ0AFjV482FcG9T6NDWbrtmmG88C8Sex3Ue2ZW2+GuwI
+vhDHJIlV/Vp0/Elp7DJa2xLDwuh+gCZvz3vs6KL+ljxrrhCyn8mp0PfsMQKBgFFZ
+KnuETOO0zVGdzFoGQTQUdP58A5+iQwsdxB+I9Ge+E80iRso3ZbhADj7VPhbbR3D2
+b6LuhImluQrUzBpsEOAnU7vGCVPSGdBuIDiBaSKebsn2gYeZPWNtdQQ0YZq2dqek
+Cb/0mfIuipzsvf7qnSza62F7q4IyqVegMegI+Jg5AoGATM3NMy7JZeKzSkm+3ohU
+3xZOwgqKV9SH+0OeYWpuBxT7D7FlrKKI4NJ3XN3hg2f/DJAF6dH11CPe7pk94yol
+HMbh+PQUQ6GYvAzxIOvagWboQ3lzeyubNMpyFjfOrIE/WOQCUBZ9tIwCHIarIuyi
+QRuNOj3+U8T/n1Ww352HBdw=
+-----END PRIVATE KEY-----`;
+
+export const PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlY+Qu4czdxNhzk3Cfgzf
+3tjUk0BY+Kz8pc+CfMY5vBLO5dJNpCuRBBr1DVRmW8O7NOeXPupMD/XqoAeVxRO/
+tuhXKtbKLuk25t9dJFOHZzFuZdgoMK4Whsm9aTcrGqNADC0+tHRWKrVMJ4WvXHgr
+GvmVNSa5J1X96zjbaaQb4VqCOwjvV19ZHlUNLpxz8wllI6V08wvDhhG5gdsO2SFH
+/DnyZHeUWeDrSKTC+9VvZ9d2g8U+dMdvxFv6RSxbUP6GpXjih6b5UVw0V1vOhuJq
+FCcpt4BzFzFI9mjnBRtlCZ6S67is94uamcGIk0ZQT+jvRCEDQlbWMXIbjVdQgnAV
+NQIDAQAB
+-----END PUBLIC KEY-----`;
diff --git a/e2e/.nvmrc b/e2e/.nvmrc
index 8e35034890..5bf4400f22 100644
--- a/e2e/.nvmrc
+++ b/e2e/.nvmrc
@@ -1 +1 @@
-24.14.1
+24.15.0
diff --git a/e2e/package.json b/e2e/package.json
index 6b72c1b36d..a58c709a6d 100644
--- a/e2e/package.json
+++ b/e2e/package.json
@@ -58,6 +58,6 @@
"vitest": "^4.0.0"
},
"volta": {
- "node": "24.14.1"
+ "node": "24.15.0"
}
}
diff --git a/e2e/src/responses.ts b/e2e/src/responses.ts
index 3d7971d6f0..2ec7aecb0e 100644
--- a/e2e/src/responses.ts
+++ b/e2e/src/responses.ts
@@ -2,82 +2,43 @@ import { expect } from 'vitest';
export const errorDto = {
unauthorized: {
- error: 'Unauthorized',
- statusCode: 401,
message: 'Authentication required',
- correlationId: expect.any(String),
},
unauthorizedWithMessage: (message: string) => ({
- error: 'Unauthorized',
- statusCode: 401,
message,
- correlationId: expect.any(String),
}),
forbidden: {
- error: 'Forbidden',
- statusCode: 403,
message: expect.any(String),
- correlationId: expect.any(String),
},
missingPermission: (permission: string) => ({
- error: 'Forbidden',
- statusCode: 403,
message: `Missing required permission: ${permission}`,
- correlationId: expect.any(String),
}),
wrongPassword: {
- error: 'Bad Request',
- statusCode: 400,
message: 'Wrong password',
- correlationId: expect.any(String),
},
invalidToken: {
- error: 'Unauthorized',
- statusCode: 401,
message: 'Invalid user token',
- correlationId: expect.any(String),
},
invalidShareKey: {
- error: 'Unauthorized',
- statusCode: 401,
message: 'Invalid share key',
- correlationId: expect.any(String),
},
passwordRequired: {
- error: 'Unauthorized',
- statusCode: 401,
message: 'Password required',
- correlationId: expect.any(String),
},
badRequest: (message: any = null) => ({
- error: 'Bad Request',
- statusCode: 400,
message: message ?? expect.anything(),
- correlationId: expect.any(String),
}),
noPermission: {
- error: 'Bad Request',
- statusCode: 400,
message: expect.stringContaining('Not found or no'),
- correlationId: expect.any(String),
},
incorrectLogin: {
- error: 'Unauthorized',
- statusCode: 401,
message: 'Incorrect email or password',
- correlationId: expect.any(String),
},
alreadyHasAdmin: {
- error: 'Bad Request',
- statusCode: 400,
message: 'The server already has an admin',
- correlationId: expect.any(String),
},
invalidEmail: {
- error: 'Bad Request',
- statusCode: 400,
message: ['email must be an email'],
- correlationId: expect.any(String),
},
};
diff --git a/e2e/src/specs/server/api/album.e2e-spec.ts b/e2e/src/specs/server/api/album.e2e-spec.ts
index 3725de8d26..e1e5178476 100644
--- a/e2e/src/specs/server/api/album.e2e-spec.ts
+++ b/e2e/src/specs/server/api/album.e2e-spec.ts
@@ -154,23 +154,31 @@ describe('/albums', () => {
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedLink,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedEditorUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedViewerUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user2.userId,
albumName: user2SharedUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user2.userId }) },
+ ]),
shared: true,
}),
]),
@@ -184,23 +192,31 @@ describe('/albums', () => {
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedEditorUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedViewerUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedLink,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1NotShared,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: false,
}),
]),
@@ -216,23 +232,31 @@ describe('/albums', () => {
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedEditorUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedViewerUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1SharedLink,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: true,
}),
expect.objectContaining({
- ownerId: user2.userId,
albumName: user2SharedUser,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user2.userId }) },
+ ]),
shared: true,
}),
]),
@@ -248,8 +272,10 @@ describe('/albums', () => {
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({
- ownerId: user1.userId,
albumName: user1NotShared,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) },
+ ]),
shared: false,
}),
]),
@@ -286,13 +312,17 @@ describe('/albums', () => {
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({
- ownerId: user4.userId,
albumName: user4DeletedAsset,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user4.userId }) },
+ ]),
shared: false,
}),
expect.objectContaining({
- ownerId: user4.userId,
albumName: user4Empty,
+ albumUsers: expect.arrayContaining([
+ { role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user4.userId }) },
+ ]),
shared: false,
}),
]),
@@ -362,16 +392,17 @@ describe('/albums', () => {
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
- expect(body).toEqual({
- ...user2Albums[0],
- contributorCounts: [{ userId: user1.userId, assetCount: 1 }],
- assetCount: 1,
- lastModifiedAssetTimestamp: expect.any(String),
- endDate: expect.any(String),
- startDate: expect.any(String),
- albumUsers: expect.any(Array),
- shared: true,
- });
+ expect(body).toEqual(
+ expect.objectContaining({
+ contributorCounts: [{ userId: user1.userId, assetCount: 1 }],
+ assetCount: 1,
+ lastModifiedAssetTimestamp: expect.any(String),
+ endDate: expect.any(String),
+ startDate: expect.any(String),
+ albumUsers: expect.any(Array),
+ shared: true,
+ }),
+ );
});
});
@@ -397,15 +428,13 @@ describe('/albums', () => {
id: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String),
- ownerId: user1.userId,
albumName: 'New album',
description: '',
albumThumbnailAssetId: null,
shared: false,
- albumUsers: [],
+ albumUsers: [{ role: AlbumUserRole.Owner, user: expect.objectContaining({ id: user1.userId }) }],
hasSharedLink: false,
assetCount: 0,
- owner: expect.objectContaining({ email: user1.userEmail }),
isActivityEnabled: true,
order: AssetOrder.Desc,
});
@@ -621,11 +650,11 @@ describe('/albums', () => {
expect(status).toBe(200);
expect(body).toEqual(
expect.objectContaining({
- albumUsers: [
+ albumUsers: expect.arrayContaining([
expect.objectContaining({
user: expect.objectContaining({ id: user2.userId }),
}),
- ],
+ ]),
}),
);
});
@@ -637,7 +666,7 @@ describe('/albums', () => {
.send({ albumUsers: [{ userId: user1.userId, role: AlbumUserRole.Editor }] });
expect(status).toBe(400);
- expect(body).toEqual(errorDto.badRequest('Cannot be shared with owner'));
+ expect(body).toEqual(errorDto.badRequest('User already added'));
});
it('should not be able to add existing user to shared album', async () => {
@@ -663,7 +692,7 @@ describe('/albums', () => {
albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Viewer }],
});
- expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer);
+ expect(album.albumUsers[1].role).toEqual(AlbumUserRole.Viewer);
const { status } = await request(app)
.put(`/albums/${album.id}/user/${user2.userId}`)
@@ -678,7 +707,10 @@ describe('/albums', () => {
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(body).toEqual(
expect.objectContaining({
- albumUsers: [expect.objectContaining({ role: AlbumUserRole.Editor })],
+ albumUsers: [
+ expect.objectContaining({ role: AlbumUserRole.Owner }),
+ expect.objectContaining({ role: AlbumUserRole.Editor }),
+ ],
}),
);
});
@@ -689,7 +721,7 @@ describe('/albums', () => {
albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Viewer }],
});
- expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer);
+ expect(album.albumUsers[1].role).toEqual(AlbumUserRole.Viewer);
const { status, body } = await request(app)
.put(`/albums/${album.id}/user/${user2.userId}`)
diff --git a/e2e/src/specs/server/api/oauth.e2e-spec.ts b/e2e/src/specs/server/api/oauth.e2e-spec.ts
index 98cb28c821..157fdfc84c 100644
--- a/e2e/src/specs/server/api/oauth.e2e-spec.ts
+++ b/e2e/src/specs/server/api/oauth.e2e-spec.ts
@@ -1,9 +1,10 @@
-import { OAuthClient, OAuthUser } from '@immich/e2e-auth-server';
+import { OAuthClient, OAuthUser, generateLogoutToken } from '@immich/e2e-auth-server';
import {
LoginResponseDto,
SystemConfigOAuthDto,
getConfigDefaults,
getMyUser,
+ getSessions,
startOAuth,
updateConfig,
} from '@immich/sdk';
@@ -88,17 +89,19 @@ describe(`/oauth`, () => {
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup();
-
- await setupOAuth(admin.accessToken, {
- enabled: true,
- clientId: OAuthClient.DEFAULT,
- clientSecret: OAuthClient.DEFAULT,
- buttonText: 'Login with Immich',
- storageLabelClaim: 'immich_username',
- });
});
describe('POST /oauth/authorize', () => {
+ beforeAll(async () => {
+ await setupOAuth(admin.accessToken, {
+ enabled: true,
+ clientId: OAuthClient.DEFAULT,
+ clientSecret: OAuthClient.DEFAULT,
+ buttonText: 'Login with Immich',
+ storageLabelClaim: 'immich_username',
+ });
+ });
+
it(`should throw an error if a redirect uri is not provided`, async () => {
const { status, body } = await request(app).post('/oauth/authorize').send({});
expect(status).toBe(400);
@@ -118,9 +121,46 @@ describe(`/oauth`, () => {
expect(params.get('redirect_uri')).toBe('http://127.0.0.1:2285/auth/login');
expect(params.get('state')).toBeDefined();
});
+
+ it('should not include the prompt parameter when not configured', async () => {
+ const { status, body } = await request(app)
+ .post('/oauth/authorize')
+ .send({ redirectUri: 'http://127.0.0.1:2285/auth/login' });
+ expect(status).toBe(201);
+
+ const params = new URL(body.url).searchParams;
+ expect(params.get('prompt')).toBeNull();
+ });
+
+ it('should include the prompt parameter when configured', async () => {
+ await setupOAuth(admin.accessToken, {
+ enabled: true,
+ clientId: OAuthClient.DEFAULT,
+ clientSecret: OAuthClient.DEFAULT,
+ prompt: 'select_account',
+ });
+
+ const { status, body } = await request(app)
+ .post('/oauth/authorize')
+ .send({ redirectUri: 'http://127.0.0.1:2285/auth/login' });
+ expect(status).toBe(201);
+
+ const params = new URL(body.url).searchParams;
+ expect(params.get('prompt')).toBe('select_account');
+ });
});
describe('POST /oauth/callback', () => {
+ beforeAll(async () => {
+ await setupOAuth(admin.accessToken, {
+ enabled: true,
+ clientId: OAuthClient.DEFAULT,
+ clientSecret: OAuthClient.DEFAULT,
+ buttonText: 'Login with Immich',
+ storageLabelClaim: 'immich_username',
+ });
+ });
+
it(`should throw an error if a url is not provided`, async () => {
const { status, body } = await request(app).post('/oauth/callback').send({});
expect(status).toBe(400);
@@ -159,10 +199,9 @@ describe(`/oauth`, () => {
it(`should throw an error if the codeVerifier doesn't match the challenge`, async () => {
const callbackParams = await loginWithOAuth('oauth-auto-register');
const { codeVerifier } = await loginWithOAuth('oauth-auto-register');
- const { status, body } = await request(app)
+ const { status } = await request(app)
.post('/oauth/callback')
.send({ ...callbackParams, codeVerifier });
- console.log(body);
expect(status).toBeGreaterThanOrEqual(400);
});
@@ -293,9 +332,7 @@ describe(`/oauth`, () => {
const { status, body } = await request(app).post('/oauth/callback').send(callbackParams);
expect(status).toBe(500);
expect(body).toMatchObject({
- error: 'Internal Server Error',
message: 'Failed to finish oauth',
- statusCode: 500,
});
});
@@ -334,6 +371,50 @@ describe(`/oauth`, () => {
});
});
+ describe(`POST /oauth/backchannel-logout`, () => {
+ it(`should throw an error if the logout_token is not provided`, async () => {
+ const { status, body } = await request(app).post('/oauth/backchannel-logout').send({});
+ expect(status).toBe(400);
+ expect(body).toEqual(errorDto.badRequest(['[logout_token] Invalid input: expected string, received undefined']));
+ });
+
+ it(`should throw an error if an invalid logout token is provided`, async () => {
+ const { status, body } = await request(app)
+ .post('/oauth/backchannel-logout')
+ .send({ logout_token: 'invalid token' });
+ expect(status).toBe(400);
+ expect(body).toEqual(errorDto.badRequest('Error backchannel logout: token validation failed'));
+ });
+
+ it(`should logout user if a valid logout token is provided`, async () => {
+ await setupOAuth(admin.accessToken, {
+ enabled: true,
+ clientId: OAuthClient.DEFAULT,
+ clientSecret: OAuthClient.DEFAULT,
+ autoRegister: true,
+ signingAlgorithm: 'RS256',
+ buttonText: 'Login with Immich',
+ });
+
+ const callbackParams = await loginWithOAuth('backchannel-logout-user');
+ const { status: callbackStatus, body: callbackBody } = await request(app)
+ .post('/oauth/callback')
+ .send(callbackParams);
+ expect(callbackStatus).toBe(201);
+
+ await expect(getSessions({ headers: asBearerAuth(callbackBody.accessToken) })).resolves.toHaveLength(1);
+
+ const logoutToken = await generateLogoutToken('http://0.0.0.0:2286', 'backchannel-logout-user');
+ const { status, body } = await request(app).post('/oauth/backchannel-logout').send({ logout_token: logoutToken });
+ expect(status).toBe(200);
+ expect(body).toMatchObject({});
+
+ await expect(getSessions({ headers: asBearerAuth(callbackBody.accessToken) })).rejects.toMatchObject({
+ status: 401,
+ });
+ });
+ });
+
describe('mobile redirect override', () => {
beforeAll(async () => {
await setupOAuth(admin.accessToken, {
@@ -412,11 +493,10 @@ describe(`/oauth`, () => {
});
it('should reject OAuth discovery over HTTP', async () => {
- const { status, body } = await request(app)
+ const { status } = await request(app)
.post('/oauth/authorize')
.send({ redirectUri: 'http://127.0.0.1:2285/auth/login' });
expect(status).toBe(500);
- expect(body).toMatchObject({ statusCode: 500 });
});
});
});
diff --git a/e2e/src/specs/server/api/server.e2e-spec.ts b/e2e/src/specs/server/api/server.e2e-spec.ts
index 3dd6f15e71..1220e6cab5 100644
--- a/e2e/src/specs/server/api/server.e2e-spec.ts
+++ b/e2e/src/specs/server/api/server.e2e-spec.ts
@@ -207,16 +207,6 @@ describe('/server', () => {
});
});
- describe('GET /server/theme', () => {
- it('should respond with the server theme', async () => {
- const { status, body } = await request(app).get('/server/theme');
- expect(status).toBe(200);
- expect(body).toEqual({
- customCss: '',
- });
- });
- });
-
describe('GET /server/license', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server/license');
diff --git a/e2e/src/specs/web/asset-viewer/detail-panel.e2e-spec.ts b/e2e/src/specs/web/asset-viewer/detail-panel.e2e-spec.ts
index 2f90e4e3d8..bbe0ef328f 100644
--- a/e2e/src/specs/web/asset-viewer/detail-panel.e2e-spec.ts
+++ b/e2e/src/specs/web/asset-viewer/detail-panel.e2e-spec.ts
@@ -1,7 +1,9 @@
import { AssetMediaResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
import { expect, test } from '@playwright/test';
+import { readFile } from 'node:fs/promises';
+import { basename, join } from 'node:path';
import type { Socket } from 'socket.io-client';
-import { utils } from 'src/utils';
+import { testAssetDir, utils } from 'src/utils';
test.describe('Detail Panel', () => {
let admin: LoginResponseDto;
@@ -83,4 +85,42 @@ test.describe('Detail Panel', () => {
await utils.waitForWebsocketEvent({ event: 'assetUpdate', id: asset.id });
await expect(textarea).toHaveValue('new description');
});
+
+ test.describe('Date editor', () => {
+ test('displays inferred asset timezone', async ({ context, page }) => {
+ const test = {
+ filepath: 'metadata/dates/datetimeoriginal-gps.jpg',
+ expected: {
+ dateTime: '2025-12-01T11:30',
+ // Test with a timezone which is NOT the first among timezones with the same offset
+ // This is to check that the editor does not simply fall back to the first available timezone with that offset
+ // America/Denver (-07:00) is not the first among timezones with offset -07:00
+ timeZoneWithOffset: 'America/Denver (-07:00)',
+ },
+ };
+
+ const asset = await utils.createAsset(admin.accessToken, {
+ assetData: {
+ bytes: await readFile(join(testAssetDir, test.filepath)),
+ filename: basename(test.filepath),
+ },
+ });
+
+ await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
+
+ // asset viewer -> detail panel -> date editor
+ await utils.setAuthCookies(context, admin.accessToken);
+ await page.goto(`/photos/${asset.id}`);
+ await page.waitForSelector('#immich-asset-viewer');
+
+ await page.getByRole('button', { name: 'Info' }).click();
+ await page.getByTestId('detail-panel-edit-date-button').click();
+ await page.waitForSelector('[role="dialog"]');
+
+ const datetime = page.locator('#datetime');
+ await expect(datetime).toHaveValue(test.expected.dateTime);
+ const timezone = page.getByRole('combobox', { name: 'Timezone' });
+ await expect(timezone).toHaveValue(test.expected.timeZoneWithOffset);
+ });
+ });
});
diff --git a/e2e/src/ui/generators/timeline/rest-response.ts b/e2e/src/ui/generators/timeline/rest-response.ts
index 8fc9ce331d..83a60556be 100644
--- a/e2e/src/ui/generators/timeline/rest-response.ts
+++ b/e2e/src/ui/generators/timeline/rest-response.ts
@@ -3,6 +3,7 @@
*/
import {
+ AlbumUserRole,
AssetTypeEnum,
AssetVisibility,
UserAvatarColor,
@@ -420,9 +421,7 @@ export function getAlbum(
albumThumbnailAssetId: album.thumbnailAssetId,
createdAt: album.createdAt,
updatedAt: album.updatedAt,
- ownerId: albumOwner.id,
- owner: albumOwner,
- albumUsers: [], // Empty array for non-shared album
+ albumUsers: [{ user: albumOwner, role: AlbumUserRole.Owner }],
shared: false,
hasSharedLink: false,
isActivityEnabled: true,
diff --git a/e2e/src/ui/mock-network/base-network.ts b/e2e/src/ui/mock-network/base-network.ts
index 7c4aee59e3..3dc3580396 100644
--- a/e2e/src/ui/mock-network/base-network.ts
+++ b/e2e/src/ui/mock-network/base-network.ts
@@ -223,6 +223,7 @@ export const setupBaseMockApiRoutes = async (context: BrowserContext, adminUserI
'.jp2',
'.jpe',
'.jxl',
+ '.mpo',
'.svg',
'.tif',
'.tiff',
diff --git a/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts b/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts
index 6a7ce82672..5069a46a91 100644
--- a/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts
+++ b/e2e/src/ui/specs/timeline/timeline.e2e-spec.ts
@@ -349,7 +349,7 @@ test.describe('Timeline', () => {
expect(visibleMockAssetsYearMonths).toContain(month);
}
});
- test('Deep link to last photo, scroll up', async ({ page }) => {
+ test.skip('Deep link to last photo, scroll up', async ({ page }) => {
const lastAsset = assets.at(-1)!;
await pageUtils.deepLinkPhotosPage(page, lastAsset.id);
@@ -361,7 +361,7 @@ test.describe('Timeline', () => {
await thumbnailUtils.expectInViewport(page, '14e5901f-fd7f-40c0-b186-4d7e7fc67968');
});
- test('Deep link to first bucket, scroll down', async ({ page }) => {
+ test.skip('Deep link to first bucket, scroll down', async ({ page }) => {
const lastAsset = assets.at(0)!;
await pageUtils.deepLinkPhotosPage(page, lastAsset.id);
await timelineUtils.locator(page).hover();
@@ -440,7 +440,7 @@ test.describe('Timeline', () => {
await thumbnailUtils.expectInViewport(page, asset.id);
await thumbnailUtils.expectSelectedDisabled(page, asset.id);
});
- test('Add photos to album', async ({ page }) => {
+ test.skip('Add photos to album', async ({ page }) => {
const album = timelineRestData.album;
await pageUtils.openAlbumPage(page, album.id);
await page.locator('nav button[aria-label="Add photos"]').click();
@@ -752,7 +752,7 @@ test.describe('Timeline', () => {
await page.getByText('Photos', { exact: true }).click();
await thumbnailUtils.expectInViewport(page, assetToFavorite.id);
});
- test('open /favorites, archive photo, unarchive photo', async ({ page }) => {
+ test.skip('open /favorites, archive photo, unarchive photo', async ({ page }) => {
await pageUtils.openFavorites(page);
const assetToArchive = getAsset(timelineRestData, 'ad31e29f-2069-4574-b9a9-ad86523c92cb')!;
await thumbnailUtils.withAssetId(page, assetToArchive.id).hover();
diff --git a/e2e/test-assets b/e2e/test-assets
index 163c251744..0eac5a3738 160000
--- a/e2e/test-assets
+++ b/e2e/test-assets
@@ -1 +1 @@
-Subproject commit 163c251744e0a35d7ecfd02682452043f149fc2b
+Subproject commit 0eac5a37384c151be88381b41f9e28d8d59a4466
diff --git a/i18n/en.json b/i18n/en.json
index 4f608f890d..add755c05d 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -276,9 +276,11 @@
"oauth_button_text": "Button text",
"oauth_client_secret_description": "Required for confidential client, or if PKCE (Proof Key for Code Exchange) is not supported for public client.",
"oauth_enable_description": "Login with OAuth",
+ "oauth_end_session_url_description": "Redirect the user to this URI when they log out.",
"oauth_mobile_redirect_uri": "Mobile redirect URI",
"oauth_mobile_redirect_uri_override": "Mobile redirect URI override",
"oauth_mobile_redirect_uri_override_description": "Enable when OAuth provider does not allow a mobile URI, like ''{callback}''",
+ "oauth_prompt_description": "Prompt parameter (e.g. select_account, login, consent)",
"oauth_role_claim": "Role Claim",
"oauth_role_claim_description": "Automatically grant admin access based on the presence of this claim. The claim may have either 'user' or 'admin'.",
"oauth_settings": "OAuth",
diff --git a/machine-learning/Dockerfile b/machine-learning/Dockerfile
index 8126ff0859..46c32f3d6a 100644
--- a/machine-learning/Dockerfile
+++ b/machine-learning/Dockerfile
@@ -48,14 +48,14 @@ FROM python:3.13-slim-trixie@sha256:d168b8d9eb761f4d3fe305ebd04aeb7e7f2de0297cec
RUN apt-get update && \
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
- wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/v2.28.4/intel-igc-core-2_2.28.4+20760_amd64.deb && \
- wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/v2.28.4/intel-igc-opencl-2_2.28.4+20760_amd64.deb && \
- wget -nv https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/intel-opencl-icd_26.05.37020.3-0_amd64.deb && \
+ wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/v2.32.7/intel-igc-core-2_2.32.7+21184_amd64.deb && \
+ wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/v2.32.7/intel-igc-opencl-2_2.32.7+21184_amd64.deb && \
+ wget -nv https://github.com/intel/compute-runtime/releases/download/26.14.37833.4/intel-opencl-icd_26.14.37833.4-0_amd64.deb && \
wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.24/intel-igc-core_1.0.17537.24_amd64.deb && \
wget -nv https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17537.24/intel-igc-opencl_1.0.17537.24_amd64.deb && \
wget -nv https://github.com/intel/compute-runtime/releases/download/24.35.30872.36/intel-opencl-icd-legacy1_24.35.30872.36_amd64.deb && \
# TODO: Figure out how to get renovate to manage this differently versioned libigdgmm file
- wget -nv https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/libigdgmm12_22.9.0_amd64.deb && \
+ wget -nv https://github.com/intel/compute-runtime/releases/download/26.14.37833.4/libigdgmm12_22.9.0_amd64.deb && \
dpkg -i *.deb && \
rm *.deb && \
apt-get remove wget -yqq && \
diff --git a/machine-learning/immich_ml/main.py b/machine-learning/immich_ml/main.py
index e7e3a719bb..4fca7a2e2b 100644
--- a/machine-learning/immich_ml/main.py
+++ b/machine-learning/immich_ml/main.py
@@ -183,7 +183,10 @@ async def predict(
text: str | None = Form(default=None),
) -> Any:
if image is not None:
- inputs: Image | str = await run(lambda: decode_pil(image))
+ decoded = await run(lambda: decode_pil(image))
+ if decoded.width == 0 or decoded.height == 0:
+ raise HTTPException(400, "Image has zero width or height")
+ inputs: Image | str = decoded
elif text is not None:
inputs = text
else:
diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml
index 640996f54a..d61df51e38 100644
--- a/machine-learning/pyproject.toml
+++ b/machine-learning/pyproject.toml
@@ -9,12 +9,12 @@ dependencies = [
"aiocache>=0.12.1,<1.0",
"fastapi>=0.95.2,<1.0",
"gunicorn>=21.1.0",
- "huggingface-hub>=0.20.1,<1.0",
+ "huggingface-hub>=1.0,<2.0",
"insightface>=0.7.3,<1.0",
"numpy<2.4.0",
"opencv-python-headless>=4.7.0.72,<5.0",
"orjson>=3.9.5",
- "pillow>=12.2,<12.3",
+ "pillow>=12.2,<13",
"pydantic>=2.0.0,<3",
"pydantic-settings>=2.5.2,<3",
"python-multipart>=0.0.6,<1.0",
diff --git a/machine-learning/test_main.py b/machine-learning/test_main.py
index 0182c57c67..cce334e40e 100644
--- a/machine-learning/test_main.py
+++ b/machine-learning/test_main.py
@@ -1198,6 +1198,19 @@ class TestLoad:
mock_model.model_format = ModelFormat.ONNX
+@pytest.mark.parametrize("size", [(0, 100), (100, 0), (0, 0)])
+def test_predict_rejects_empty_image(size: tuple[int, int], deployed_app: TestClient) -> None:
+ with mock.patch("immich_ml.main.decode_pil", return_value=Image.new("RGB", size)):
+ response = deployed_app.post(
+ "http://localhost:3003/predict",
+ data={"entries": json.dumps({"clip": {"visual": {"modelName": "ViT-B-32__openai"}}})},
+ files={"image": b"fake image bytes"},
+ )
+
+ assert response.status_code == 400
+ assert "zero" in response.json()["detail"].lower()
+
+
def test_root_endpoint(deployed_app: TestClient) -> None:
response = deployed_app.get("http://localhost:3003")
diff --git a/mise.toml b/mise.toml
index d299bac847..d2bda7d8a2 100644
--- a/mise.toml
+++ b/mise.toml
@@ -14,11 +14,11 @@ config_roots = [
]
[tools]
-node = "24.14.1"
-flutter = "3.35.7"
-pnpm = "10.33.0"
-terragrunt = "1.0.0"
-opentofu = "1.11.5"
+node = "24.15.0"
+flutter = "3.41.6"
+pnpm = "10.33.1"
+terragrunt = "1.0.2"
+opentofu = "1.11.6"
java = "21.0.2"
[tools."github:CQLabs/homebrew-dcm"]
diff --git a/mobile/.vscode/settings.json b/mobile/.vscode/settings.json
index 1bb94819e5..051c18ce6a 100644
--- a/mobile/.vscode/settings.json
+++ b/mobile/.vscode/settings.json
@@ -1,5 +1,5 @@
{
- "dart.flutterSdkPath": ".fvm/versions/3.41.6",
+ "dart.flutterSdkPath": ".fvm/versions/3.41.7",
"dart.lineLength": 120,
"[dart]": {
"editor.rulers": [
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundEngineLock.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundEngineLock.kt
index b11b53bcde..bcd7eeee18 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundEngineLock.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundEngineLock.kt
@@ -43,8 +43,8 @@ class BackgroundEngineLock(context: Context) : BackgroundWorkerLockApi, ImmichPl
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
super.onAttachedToEngine(binding)
- checkAndEnforceBackgroundLock(binding.applicationContext)
engineCount.incrementAndGet()
+ checkAndEnforceBackgroundLock(binding.applicationContext)
Log.i(TAG, "Flutter engine attached. Attached Engines count: $engineCount")
}
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorker.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorker.g.kt
index b6b387db03..0ae49f87f6 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorker.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorker.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -37,36 +37,150 @@ private object BackgroundWorkerPigeonUtils {
)
}
}
+ fun doubleEquals(a: Double, b: Double): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun floatEquals(a: Float, b: Float): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun doubleHash(d: Double): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (d == 0.0) 0.0 else d
+ val bits = java.lang.Double.doubleToLongBits(normalized)
+ return (bits xor (bits ushr 32)).toInt()
+ }
+
+ fun floatHash(f: Float): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (f == 0.0f) 0.0f else f
+ return java.lang.Float.floatToIntBits(normalized)
+ }
+
fun deepEquals(a: Any?, b: Any?): Boolean {
+ if (a === b) {
+ return true
+ }
+ if (a == null || b == null) {
+ return false
+ }
if (a is ByteArray && b is ByteArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
- return a.contentEquals(b)
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!doubleEquals(a[i], b[i])) return false
+ }
+ return true
+ }
+ if (a is FloatArray && b is FloatArray) {
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!floatEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is Array<*> && b is Array<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!deepEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is List<*> && b is List<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ val iterA = a.iterator()
+ val iterB = b.iterator()
+ while (iterA.hasNext() && iterB.hasNext()) {
+ if (!deepEquals(iterA.next(), iterB.next())) return false
+ }
+ return true
}
if (a is Map<*, *> && b is Map<*, *>) {
- return a.size == b.size && a.all {
- (b as Map).containsKey(it.key) &&
- deepEquals(it.value, b[it.key])
+ if (a.size != b.size) return false
+ for (entry in a) {
+ val key = entry.key
+ var found = false
+ for (bEntry in b) {
+ if (deepEquals(key, bEntry.key)) {
+ if (deepEquals(entry.value, bEntry.value)) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if (!found) return false
}
+ return true
+ }
+ if (a is Double && b is Double) {
+ return doubleEquals(a, b)
+ }
+ if (a is Float && b is Float) {
+ return floatEquals(a, b)
}
return a == b
}
-
+
+ fun deepHash(value: Any?): Int {
+ return when (value) {
+ null -> 0
+ is ByteArray -> value.contentHashCode()
+ is IntArray -> value.contentHashCode()
+ is LongArray -> value.contentHashCode()
+ is DoubleArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + doubleHash(item)
+ }
+ result
+ }
+ is FloatArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + floatHash(item)
+ }
+ result
+ }
+ is Array<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is List<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is Map<*, *> -> {
+ var result = 0
+ for (entry in value) {
+ result += ((deepHash(entry.key) * 31) xor deepHash(entry.value))
+ }
+ result
+ }
+ is Double -> doubleHash(value)
+ is Float -> floatHash(value)
+ else -> value.hashCode()
+ }
+ }
+
}
/**
@@ -79,7 +193,7 @@ class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
-) : Throwable()
+) : RuntimeException()
/** Generated class from Pigeon that represents data sent in messages. */
data class BackgroundWorkerSettings (
@@ -101,15 +215,22 @@ data class BackgroundWorkerSettings (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is BackgroundWorkerSettings) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return BackgroundWorkerPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as BackgroundWorkerSettings
+ return BackgroundWorkerPigeonUtils.deepEquals(this.requiresCharging, other.requiresCharging) && BackgroundWorkerPigeonUtils.deepEquals(this.minimumDelaySeconds, other.minimumDelaySeconds)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + BackgroundWorkerPigeonUtils.deepHash(this.requiresCharging)
+ result = 31 * result + BackgroundWorkerPigeonUtils.deepHash(this.minimumDelaySeconds)
+ return result
+ }
}
private open class BackgroundWorkerPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerApiImpl.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerApiImpl.kt
index a78db3c5ea..bc0766bee5 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerApiImpl.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerApiImpl.kt
@@ -5,8 +5,10 @@ import android.provider.MediaStore
import android.util.Log
import androidx.work.BackoffPolicy
import androidx.work.Constraints
+import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ExistingWorkPolicy
-import androidx.work.OneTimeWorkRequest
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import io.flutter.embedding.engine.FlutterEngineCache
import java.util.concurrent.TimeUnit
@@ -18,6 +20,7 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
override fun enable() {
enqueueMediaObserver(ctx)
+ enqueuePeriodicWorker(ctx)
}
override fun saveNotificationMessage(title: String, body: String) {
@@ -27,12 +30,14 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
override fun configure(settings: BackgroundWorkerSettings) {
BackgroundWorkerPreferences(ctx).updateSettings(settings)
enqueueMediaObserver(ctx)
+ enqueuePeriodicWorker(ctx)
}
override fun disable() {
WorkManager.getInstance(ctx).apply {
cancelUniqueWork(OBSERVER_WORKER_NAME)
cancelUniqueWork(BACKGROUND_WORKER_NAME)
+ cancelUniqueWork(PERIODIC_WORKER_NAME)
}
Log.i(TAG, "Cancelled background upload tasks")
}
@@ -40,6 +45,7 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
companion object {
private const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
private const val OBSERVER_WORKER_NAME = "immich/MediaObserverV1"
+ private const val PERIODIC_WORKER_NAME = "immich/PeriodicBackgroundWorkerV1"
const val ENGINE_CACHE_KEY = "immich::background_worker::engine"
@@ -55,7 +61,7 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
setRequiresCharging(settings.requiresCharging)
}.build()
- val work = OneTimeWorkRequest.Builder(MediaObserver::class.java)
+ val work = OneTimeWorkRequestBuilder()
.setConstraints(constraints)
.build()
WorkManager.getInstance(ctx)
@@ -67,10 +73,30 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
)
}
+ fun enqueuePeriodicWorker(ctx: Context) {
+ val settings = BackgroundWorkerPreferences(ctx).getSettings()
+ val constraints = Constraints.Builder().apply {
+ setRequiresCharging(settings.requiresCharging)
+ }.build()
+
+ val work =
+ PeriodicWorkRequestBuilder(
+ 1,
+ TimeUnit.HOURS,
+ 15,
+ TimeUnit.MINUTES
+ ).setConstraints(constraints)
+ .build()
+
+ WorkManager.getInstance(ctx)
+ .enqueueUniquePeriodicWork(PERIODIC_WORKER_NAME, ExistingPeriodicWorkPolicy.UPDATE, work)
+
+ Log.i(TAG, "Enqueued periodic background worker with name: $PERIODIC_WORKER_NAME")
+ }
+
fun enqueueBackgroundWorker(ctx: Context) {
val constraints = Constraints.Builder().setRequiresBatteryNotLow(true).build()
-
- val work = OneTimeWorkRequest.Builder(BackgroundWorker::class.java)
+ val work = OneTimeWorkRequestBuilder()
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
.build()
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerLock.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerLock.g.kt
index d7353f0462..4e2e382c2b 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerLock.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/BackgroundWorkerLock.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/background/PeriodicWorker.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/PeriodicWorker.kt
new file mode 100644
index 0000000000..d4ecde9bbb
--- /dev/null
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/background/PeriodicWorker.kt
@@ -0,0 +1,16 @@
+package app.alextran.immich.background
+
+import android.content.Context
+import android.util.Log
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+
+class PeriodicWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
+ private val ctx: Context = context.applicationContext
+
+ override fun doWork(): Result {
+ Log.i("PeriodicWorker", "Periodic worker triggered, starting background worker")
+ BackgroundWorkerApiImpl.enqueueBackgroundWorker(ctx)
+ return Result.success()
+ }
+}
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/connectivity/Connectivity.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/connectivity/Connectivity.g.kt
index 629071382a..aec1f06164 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/connectivity/Connectivity.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/connectivity/Connectivity.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -46,7 +46,7 @@ class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
-) : Throwable()
+) : RuntimeException()
enum class NetworkCapability(val raw: Int) {
CELLULAR(0),
@@ -75,7 +75,7 @@ private open class ConnectivityPigeonCodec : StandardMessageCodec() {
when (value) {
is NetworkCapability -> {
stream.write(129)
- writeValue(stream, value.raw)
+ writeValue(stream, value.raw.toLong())
}
else -> super.writeValue(stream, value)
}
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/core/Network.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/core/Network.g.kt
index 869e312515..1687a7ba95 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/core/Network.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/core/Network.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -34,36 +34,150 @@ private object NetworkPigeonUtils {
)
}
}
+ fun doubleEquals(a: Double, b: Double): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun floatEquals(a: Float, b: Float): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun doubleHash(d: Double): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (d == 0.0) 0.0 else d
+ val bits = java.lang.Double.doubleToLongBits(normalized)
+ return (bits xor (bits ushr 32)).toInt()
+ }
+
+ fun floatHash(f: Float): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (f == 0.0f) 0.0f else f
+ return java.lang.Float.floatToIntBits(normalized)
+ }
+
fun deepEquals(a: Any?, b: Any?): Boolean {
+ if (a === b) {
+ return true
+ }
+ if (a == null || b == null) {
+ return false
+ }
if (a is ByteArray && b is ByteArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
- return a.contentEquals(b)
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!doubleEquals(a[i], b[i])) return false
+ }
+ return true
+ }
+ if (a is FloatArray && b is FloatArray) {
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!floatEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is Array<*> && b is Array<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!deepEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is List<*> && b is List<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ val iterA = a.iterator()
+ val iterB = b.iterator()
+ while (iterA.hasNext() && iterB.hasNext()) {
+ if (!deepEquals(iterA.next(), iterB.next())) return false
+ }
+ return true
}
if (a is Map<*, *> && b is Map<*, *>) {
- return a.size == b.size && a.all {
- (b as Map).containsKey(it.key) &&
- deepEquals(it.value, b[it.key])
+ if (a.size != b.size) return false
+ for (entry in a) {
+ val key = entry.key
+ var found = false
+ for (bEntry in b) {
+ if (deepEquals(key, bEntry.key)) {
+ if (deepEquals(entry.value, bEntry.value)) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if (!found) return false
}
+ return true
+ }
+ if (a is Double && b is Double) {
+ return doubleEquals(a, b)
+ }
+ if (a is Float && b is Float) {
+ return floatEquals(a, b)
}
return a == b
}
-
+
+ fun deepHash(value: Any?): Int {
+ return when (value) {
+ null -> 0
+ is ByteArray -> value.contentHashCode()
+ is IntArray -> value.contentHashCode()
+ is LongArray -> value.contentHashCode()
+ is DoubleArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + doubleHash(item)
+ }
+ result
+ }
+ is FloatArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + floatHash(item)
+ }
+ result
+ }
+ is Array<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is List<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is Map<*, *> -> {
+ var result = 0
+ for (entry in value) {
+ result += ((deepHash(entry.key) * 31) xor deepHash(entry.value))
+ }
+ result
+ }
+ is Double -> doubleHash(value)
+ is Float -> floatHash(value)
+ else -> value.hashCode()
+ }
+ }
+
}
/**
@@ -76,7 +190,7 @@ class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
-) : Throwable()
+) : RuntimeException()
/** Generated class from Pigeon that represents data sent in messages. */
data class ClientCertData (
@@ -98,15 +212,22 @@ data class ClientCertData (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is ClientCertData) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return NetworkPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as ClientCertData
+ return NetworkPigeonUtils.deepEquals(this.data, other.data) && NetworkPigeonUtils.deepEquals(this.password, other.password)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.data)
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.password)
+ return result
+ }
}
/** Generated class from Pigeon that represents data sent in messages. */
@@ -135,15 +256,24 @@ data class ClientCertPrompt (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is ClientCertPrompt) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return NetworkPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as ClientCertPrompt
+ return NetworkPigeonUtils.deepEquals(this.title, other.title) && NetworkPigeonUtils.deepEquals(this.message, other.message) && NetworkPigeonUtils.deepEquals(this.cancel, other.cancel) && NetworkPigeonUtils.deepEquals(this.confirm, other.confirm)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.title)
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.message)
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.cancel)
+ result = 31 * result + NetworkPigeonUtils.deepHash(this.confirm)
+ return result
+ }
}
private open class NetworkPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/LocalImages.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/LocalImages.g.kt
index 7d998c2f48..e741ce07e9 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/LocalImages.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/LocalImages.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -46,7 +46,7 @@ class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
-) : Throwable()
+) : RuntimeException()
private open class LocalImagesPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return super.readValueOfType(type, buffer)
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt
index bef6418904..2b5f4d2f57 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt
index 29c197c2b6..b49664dea5 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
@@ -34,36 +34,150 @@ private object MessagesPigeonUtils {
)
}
}
+ fun doubleEquals(a: Double, b: Double): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun floatEquals(a: Float, b: Float): Boolean {
+ // Normalize -0.0 to 0.0 and handle NaN equality.
+ return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN())
+ }
+
+ fun doubleHash(d: Double): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (d == 0.0) 0.0 else d
+ val bits = java.lang.Double.doubleToLongBits(normalized)
+ return (bits xor (bits ushr 32)).toInt()
+ }
+
+ fun floatHash(f: Float): Int {
+ // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes.
+ val normalized = if (f == 0.0f) 0.0f else f
+ return java.lang.Float.floatToIntBits(normalized)
+ }
+
fun deepEquals(a: Any?, b: Any?): Boolean {
+ if (a === b) {
+ return true
+ }
+ if (a == null || b == null) {
+ return false
+ }
if (a is ByteArray && b is ByteArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is IntArray && b is IntArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is LongArray && b is LongArray) {
- return a.contentEquals(b)
+ return a.contentEquals(b)
}
if (a is DoubleArray && b is DoubleArray) {
- return a.contentEquals(b)
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!doubleEquals(a[i], b[i])) return false
+ }
+ return true
+ }
+ if (a is FloatArray && b is FloatArray) {
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!floatEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is Array<*> && b is Array<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ for (i in a.indices) {
+ if (!deepEquals(a[i], b[i])) return false
+ }
+ return true
}
if (a is List<*> && b is List<*>) {
- return a.size == b.size &&
- a.indices.all{ deepEquals(a[it], b[it]) }
+ if (a.size != b.size) return false
+ val iterA = a.iterator()
+ val iterB = b.iterator()
+ while (iterA.hasNext() && iterB.hasNext()) {
+ if (!deepEquals(iterA.next(), iterB.next())) return false
+ }
+ return true
}
if (a is Map<*, *> && b is Map<*, *>) {
- return a.size == b.size && a.all {
- (b as Map).containsKey(it.key) &&
- deepEquals(it.value, b[it.key])
+ if (a.size != b.size) return false
+ for (entry in a) {
+ val key = entry.key
+ var found = false
+ for (bEntry in b) {
+ if (deepEquals(key, bEntry.key)) {
+ if (deepEquals(entry.value, bEntry.value)) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if (!found) return false
}
+ return true
+ }
+ if (a is Double && b is Double) {
+ return doubleEquals(a, b)
+ }
+ if (a is Float && b is Float) {
+ return floatEquals(a, b)
}
return a == b
}
-
+
+ fun deepHash(value: Any?): Int {
+ return when (value) {
+ null -> 0
+ is ByteArray -> value.contentHashCode()
+ is IntArray -> value.contentHashCode()
+ is LongArray -> value.contentHashCode()
+ is DoubleArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + doubleHash(item)
+ }
+ result
+ }
+ is FloatArray -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + floatHash(item)
+ }
+ result
+ }
+ is Array<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is List<*> -> {
+ var result = 1
+ for (item in value) {
+ result = 31 * result + deepHash(item)
+ }
+ result
+ }
+ is Map<*, *> -> {
+ var result = 0
+ for (entry in value) {
+ result += ((deepHash(entry.key) * 31) xor deepHash(entry.value))
+ }
+ result
+ }
+ is Double -> doubleHash(value)
+ is Float -> floatHash(value)
+ else -> value.hashCode()
+ }
+ }
+
}
/**
@@ -76,7 +190,7 @@ class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
-) : Throwable()
+) : RuntimeException()
enum class PlatformAssetPlaybackStyle(val raw: Int) {
UNKNOWN(0),
@@ -102,7 +216,7 @@ data class PlatformAsset (
val updatedAt: Long? = null,
val width: Long? = null,
val height: Long? = null,
- val durationInSeconds: Long,
+ val durationMs: Long,
val orientation: Long,
val isFavorite: Boolean,
val adjustmentTime: Long? = null,
@@ -120,14 +234,14 @@ data class PlatformAsset (
val updatedAt = pigeonVar_list[4] as Long?
val width = pigeonVar_list[5] as Long?
val height = pigeonVar_list[6] as Long?
- val durationInSeconds = pigeonVar_list[7] as Long
+ val durationMs = pigeonVar_list[7] as Long
val orientation = pigeonVar_list[8] as Long
val isFavorite = pigeonVar_list[9] as Boolean
val adjustmentTime = pigeonVar_list[10] as Long?
val latitude = pigeonVar_list[11] as Double?
val longitude = pigeonVar_list[12] as Double?
val playbackStyle = pigeonVar_list[13] as PlatformAssetPlaybackStyle
- return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite, adjustmentTime, latitude, longitude, playbackStyle)
+ return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationMs, orientation, isFavorite, adjustmentTime, latitude, longitude, playbackStyle)
}
}
fun toList(): List {
@@ -139,7 +253,7 @@ data class PlatformAsset (
updatedAt,
width,
height,
- durationInSeconds,
+ durationMs,
orientation,
isFavorite,
adjustmentTime,
@@ -149,15 +263,34 @@ data class PlatformAsset (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is PlatformAsset) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as PlatformAsset
+ return MessagesPigeonUtils.deepEquals(this.id, other.id) && MessagesPigeonUtils.deepEquals(this.name, other.name) && MessagesPigeonUtils.deepEquals(this.type, other.type) && MessagesPigeonUtils.deepEquals(this.createdAt, other.createdAt) && MessagesPigeonUtils.deepEquals(this.updatedAt, other.updatedAt) && MessagesPigeonUtils.deepEquals(this.width, other.width) && MessagesPigeonUtils.deepEquals(this.height, other.height) && MessagesPigeonUtils.deepEquals(this.durationMs, other.durationMs) && MessagesPigeonUtils.deepEquals(this.orientation, other.orientation) && MessagesPigeonUtils.deepEquals(this.isFavorite, other.isFavorite) && MessagesPigeonUtils.deepEquals(this.adjustmentTime, other.adjustmentTime) && MessagesPigeonUtils.deepEquals(this.latitude, other.latitude) && MessagesPigeonUtils.deepEquals(this.longitude, other.longitude) && MessagesPigeonUtils.deepEquals(this.playbackStyle, other.playbackStyle)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.id)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.name)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.type)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.createdAt)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.updatedAt)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.width)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.height)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.durationMs)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.orientation)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.isFavorite)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.adjustmentTime)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.latitude)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.longitude)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.playbackStyle)
+ return result
+ }
}
/** Generated class from Pigeon that represents data sent in messages. */
@@ -189,15 +322,25 @@ data class PlatformAlbum (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is PlatformAlbum) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as PlatformAlbum
+ return MessagesPigeonUtils.deepEquals(this.id, other.id) && MessagesPigeonUtils.deepEquals(this.name, other.name) && MessagesPigeonUtils.deepEquals(this.updatedAt, other.updatedAt) && MessagesPigeonUtils.deepEquals(this.isCloud, other.isCloud) && MessagesPigeonUtils.deepEquals(this.assetCount, other.assetCount)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.id)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.name)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.updatedAt)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.isCloud)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.assetCount)
+ return result
+ }
}
/** Generated class from Pigeon that represents data sent in messages. */
@@ -226,15 +369,24 @@ data class SyncDelta (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is SyncDelta) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as SyncDelta
+ return MessagesPigeonUtils.deepEquals(this.hasChanges, other.hasChanges) && MessagesPigeonUtils.deepEquals(this.updates, other.updates) && MessagesPigeonUtils.deepEquals(this.deletes, other.deletes) && MessagesPigeonUtils.deepEquals(this.assetAlbums, other.assetAlbums)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.hasChanges)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.updates)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.deletes)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.assetAlbums)
+ return result
+ }
}
/** Generated class from Pigeon that represents data sent in messages. */
@@ -260,15 +412,23 @@ data class HashResult (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is HashResult) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as HashResult
+ return MessagesPigeonUtils.deepEquals(this.assetId, other.assetId) && MessagesPigeonUtils.deepEquals(this.error, other.error) && MessagesPigeonUtils.deepEquals(this.hash, other.hash)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.assetId)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.error)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.hash)
+ return result
+ }
}
/** Generated class from Pigeon that represents data sent in messages. */
@@ -294,15 +454,23 @@ data class CloudIdResult (
)
}
override fun equals(other: Any?): Boolean {
- if (other !is CloudIdResult) {
+ if (other == null || other.javaClass != javaClass) {
return false
}
if (this === other) {
return true
}
- return MessagesPigeonUtils.deepEquals(toList(), other.toList()) }
+ val other = other as CloudIdResult
+ return MessagesPigeonUtils.deepEquals(this.assetId, other.assetId) && MessagesPigeonUtils.deepEquals(this.error, other.error) && MessagesPigeonUtils.deepEquals(this.cloudId, other.cloudId)
+ }
- override fun hashCode(): Int = toList().hashCode()
+ override fun hashCode(): Int {
+ var result = javaClass.hashCode()
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.assetId)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.error)
+ result = 31 * result + MessagesPigeonUtils.deepHash(this.cloudId)
+ return result
+ }
}
private open class MessagesPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
@@ -344,7 +512,7 @@ private open class MessagesPigeonCodec : StandardMessageCodec() {
when (value) {
is PlatformAssetPlaybackStyle -> {
stream.write(129)
- writeValue(stream, value.raw)
+ writeValue(stream, value.raw.toLong())
}
is PlatformAsset -> {
stream.write(130)
diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt
index eea66db2f6..777a565fe3 100644
--- a/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt
+++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/sync/MessagesImplBase.kt
@@ -178,7 +178,7 @@ open class NativeSyncApiImplBase(context: Context) : ImmichPlugin() {
val height = c.getInt(heightColumn).toLong()
// Duration is milliseconds
val duration = if (rawMediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) 0L
- else c.getLong(durationColumn) / 1000
+ else c.getLong(durationColumn)
val orientation = c.getInt(orientationColumn)
val isFavorite = if (favoriteColumn == -1) false else c.getInt(favoriteColumn) != 0
diff --git a/mobile/android/gradle/libs.versions.toml b/mobile/android/gradle/libs.versions.toml
index 0161433c05..fa4ba34a2d 100644
--- a/mobile/android/gradle/libs.versions.toml
+++ b/mobile/android/gradle/libs.versions.toml
@@ -46,6 +46,6 @@ material = { module = "com.google.android.material:material", version.ref = "mat
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
# TODO: update to version.ref = "kotlin" when background_downloader is removed
-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version = "1.9.22" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version = "2.1.0" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
diff --git a/mobile/android/settings.gradle b/mobile/android/settings.gradle
index 664cb9c263..d6555f43b1 100644
--- a/mobile/android/settings.gradle
+++ b/mobile/android/settings.gradle
@@ -21,7 +21,7 @@ plugins {
id "com.android.application" version "8.11.2" apply false
id "org.jetbrains.kotlin.android" version "2.2.20" apply false
// TODO: update to match kotlin version when background_downloader is removed
- id "org.jetbrains.kotlin.plugin.serialization" version "1.9.22" apply false
+ id "org.jetbrains.kotlin.plugin.serialization" version "2.1.0" apply false
id "com.google.devtools.ksp" version "2.2.20-2.0.3" apply false
}
diff --git a/mobile/drift_schemas/main/drift_schema_v23.json b/mobile/drift_schemas/main/drift_schema_v23.json
new file mode 100644
index 0000000000..490484f7e8
--- /dev/null
+++ b/mobile/drift_schemas/main/drift_schema_v23.json
@@ -0,0 +1,3351 @@
+{
+ "_meta": {
+ "description": "This file contains a serialized version of schema entities for drift.",
+ "version": "1.3.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": "email",
+ "getter_name": "email",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "has_profile_image",
+ "getter_name": "hasProfileImage",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"has_profile_image\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"has_profile_image\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "profile_changed_at",
+ "getter_name": "profileChangedAt",
+ "moor_type": "dateTime",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('CURRENT_TIMESTAMP')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "avatar_color",
+ "getter_name": "avatarColor",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AvatarColor.values)",
+ "dart_type_name": "AvatarColor"
+ }
+ }
+ ],
+ "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_ms",
+ "getter_name": "durationMs",
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": []
+ },
+ {
+ "name": "library_id",
+ "getter_name": "libraryId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_edited",
+ "getter_name": "isEdited",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_edited\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_edited\" 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": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 2,
+ "references": [
+ 0
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "primary_asset_id",
+ "getter_name": "primaryAssetId",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 3,
+ "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_ms",
+ "getter_name": "durationMs",
+ "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": []
+ },
+ {
+ "name": "i_cloud_id",
+ "getter_name": "iCloudId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "adjustment_time",
+ "getter_name": "adjustmentTime",
+ "moor_type": "dateTime",
+ "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": "playback_style",
+ "getter_name": "playbackStyle",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetPlaybackStyle.values)",
+ "dart_type_name": "AssetPlaybackStyle"
+ }
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 4,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "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": 5,
+ "references": [
+ 4
+ ],
+ "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": "linked_remote_album_id",
+ "getter_name": "linkedRemoteAlbumId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "defaultConstraints": "REFERENCES remote_album_entity (id) ON DELETE SET NULL",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "REFERENCES remote_album_entity (id) ON DELETE SET NULL"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "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": 6,
+ "references": [
+ 3,
+ 5
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "local_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "local_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ "asset_id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 7,
+ "references": [
+ 6
+ ],
+ "type": "index",
+ "data": {
+ "on": 6,
+ "name": "idx_local_album_asset_album_asset",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 8,
+ "references": [
+ 4
+ ],
+ "type": "index",
+ "data": {
+ "on": 4,
+ "name": "idx_remote_album_owner_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_owner_id ON remote_album_entity (owner_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 9,
+ "references": [
+ 3
+ ],
+ "type": "index",
+ "data": {
+ "on": 3,
+ "name": "idx_local_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 10,
+ "references": [
+ 3
+ ],
+ "type": "index",
+ "data": {
+ "on": 3,
+ "name": "idx_local_asset_cloud_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 11,
+ "references": [
+ 2
+ ],
+ "type": "index",
+ "data": {
+ "on": 2,
+ "name": "idx_stack_primary_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 12,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_owner_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 13,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "UQ_remote_assets_owner_checksum",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum\nON remote_asset_entity (owner_id, checksum)\nWHERE (library_id IS NULL);\n",
+ "unique": true,
+ "columns": []
+ }
+ },
+ {
+ "id": 14,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "UQ_remote_assets_owner_library_checksum",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum\nON remote_asset_entity (owner_id, library_id, checksum)\nWHERE (library_id IS NOT NULL);\n",
+ "unique": true,
+ "columns": []
+ }
+ },
+ {
+ "id": 15,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 16,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_stack_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 17,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_local_date_time_day",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_day ON remote_asset_entity (STRFTIME('%Y-%m-%d', local_date_time))",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 18,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_local_date_time_month",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_month ON remote_asset_entity (STRFTIME('%Y-%m', local_date_time))",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 19,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "auth_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": "email",
+ "getter_name": "email",
+ "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": "has_profile_image",
+ "getter_name": "hasProfileImage",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"has_profile_image\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"has_profile_image\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "profile_changed_at",
+ "getter_name": "profileChangedAt",
+ "moor_type": "dateTime",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('CURRENT_TIMESTAMP')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "avatar_color",
+ "getter_name": "avatarColor",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AvatarColor.values)",
+ "dart_type_name": "AvatarColor"
+ }
+ },
+ {
+ "name": "quota_size_in_bytes",
+ "getter_name": "quotaSizeInBytes",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "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": []
+ },
+ {
+ "name": "pin_code",
+ "getter_name": "pinCode",
+ "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": 20,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 21,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 22,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 23,
+ "references": [
+ 1,
+ 4
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 24,
+ "references": [
+ 4,
+ 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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 25,
+ "references": [
+ 1
+ ],
+ "type": "table",
+ "data": {
+ "name": "remote_asset_cloud_id_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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "cloud_id",
+ "getter_name": "cloudId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "created_at",
+ "getter_name": "createdAt",
+ "moor_type": "dateTime",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "adjustment_time",
+ "getter_name": "adjustmentTime",
+ "moor_type": "dateTime",
+ "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": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id"
+ ]
+ }
+ },
+ {
+ "id": 26,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 27,
+ "references": [
+ 1,
+ 26
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "memory_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id",
+ "memory_id"
+ ]
+ }
+ },
+ {
+ "id": 28,
+ "references": [
+ 0
+ ],
+ "type": "table",
+ "data": {
+ "name": "person_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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "name",
+ "getter_name": "name",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "face_asset_id",
+ "getter_name": "faceAssetId",
+ "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": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_hidden",
+ "getter_name": "isHidden",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_hidden\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_hidden\" IN (0, 1))"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "color",
+ "getter_name": "color",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "birth_date",
+ "getter_name": "birthDate",
+ "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": 29,
+ "references": [
+ 1,
+ 28
+ ],
+ "type": "table",
+ "data": {
+ "name": "asset_face_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": "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "person_id",
+ "getter_name": "personId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "defaultConstraints": "REFERENCES person_entity (id) ON DELETE SET NULL",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "REFERENCES person_entity (id) ON DELETE SET NULL"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "person_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "name": "image_width",
+ "getter_name": "imageWidth",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "image_height",
+ "getter_name": "imageHeight",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_x1",
+ "getter_name": "boundingBoxX1",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_y1",
+ "getter_name": "boundingBoxY1",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_x2",
+ "getter_name": "boundingBoxX2",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_y2",
+ "getter_name": "boundingBoxY2",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "source_type",
+ "getter_name": "sourceType",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_visible",
+ "getter_name": "isVisible",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_visible\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_visible\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('1')",
+ "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": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 30,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "store_entity",
+ "was_declared_in_moor": false,
+ "columns": [
+ {
+ "name": "id",
+ "getter_name": "id",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "string_value",
+ "getter_name": "stringValue",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "int_value",
+ "getter_name": "intValue",
+ "moor_type": "int",
+ "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": 31,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "trashed_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_ms",
+ "getter_name": "durationMs",
+ "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": "album_id",
+ "getter_name": "albumId",
+ "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": []
+ },
+ {
+ "name": "source",
+ "getter_name": "source",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(TrashOrigin.values)",
+ "dart_type_name": "TrashOrigin"
+ }
+ },
+ {
+ "name": "playback_style",
+ "getter_name": "playbackStyle",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetPlaybackStyle.values)",
+ "dart_type_name": "AssetPlaybackStyle"
+ }
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 32,
+ "references": [
+ 1
+ ],
+ "type": "table",
+ "data": {
+ "name": "asset_edit_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": "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "action",
+ "getter_name": "action",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetEditAction.values)",
+ "dart_type_name": "AssetEditAction"
+ }
+ },
+ {
+ "name": "parameters",
+ "getter_name": "parameters",
+ "moor_type": "blob",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "editParameterConverter",
+ "dart_type_name": "Map"
+ }
+ },
+ {
+ "name": "sequence",
+ "getter_name": "sequence",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 33,
+ "references": [
+ 21
+ ],
+ "type": "index",
+ "data": {
+ "on": 21,
+ "name": "idx_partner_shared_with_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 34,
+ "references": [
+ 22
+ ],
+ "type": "index",
+ "data": {
+ "on": 22,
+ "name": "idx_lat_lng",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 35,
+ "references": [
+ 23
+ ],
+ "type": "index",
+ "data": {
+ "on": 23,
+ "name": "idx_remote_album_asset_album_asset",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 36,
+ "references": [
+ 25
+ ],
+ "type": "index",
+ "data": {
+ "on": 25,
+ "name": "idx_remote_asset_cloud_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 37,
+ "references": [
+ 28
+ ],
+ "type": "index",
+ "data": {
+ "on": 28,
+ "name": "idx_person_owner_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 38,
+ "references": [
+ 29
+ ],
+ "type": "index",
+ "data": {
+ "on": 29,
+ "name": "idx_asset_face_person_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 39,
+ "references": [
+ 29
+ ],
+ "type": "index",
+ "data": {
+ "on": 29,
+ "name": "idx_asset_face_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 40,
+ "references": [
+ 31
+ ],
+ "type": "index",
+ "data": {
+ "on": 31,
+ "name": "idx_trashed_local_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 41,
+ "references": [
+ 31
+ ],
+ "type": "index",
+ "data": {
+ "on": 31,
+ "name": "idx_trashed_local_asset_album",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 42,
+ "references": [
+ 32
+ ],
+ "type": "index",
+ "data": {
+ "on": 32,
+ "name": "idx_asset_edit_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ }
+ ],
+ "fixed_sql": [
+ {
+ "name": "user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"user_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"email\" TEXT NOT NULL, \"has_profile_image\" INTEGER NOT NULL DEFAULT 0 CHECK (\"has_profile_image\" IN (0, 1)), \"profile_changed_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"avatar_color\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"checksum\" TEXT NOT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"local_date_time\" TEXT NULL, \"thumb_hash\" TEXT NULL, \"deleted_at\" TEXT NULL, \"live_photo_video_id\" TEXT NULL, \"visibility\" INTEGER NOT NULL, \"stack_id\" TEXT NULL, \"library_id\" TEXT NULL, \"is_edited\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_edited\" IN (0, 1)), PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "stack_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"stack_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"primary_asset_id\" TEXT NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"checksum\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"orientation\" INTEGER NOT NULL DEFAULT 0, \"i_cloud_id\" TEXT NULL, \"adjustment_time\" TEXT NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, \"playback_style\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"description\" TEXT NOT NULL DEFAULT '', \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"thumbnail_asset_id\" TEXT NULL REFERENCES remote_asset_entity (id) ON DELETE SET NULL, \"is_activity_enabled\" INTEGER NOT NULL DEFAULT 1 CHECK (\"is_activity_enabled\" IN (0, 1)), \"order\" INTEGER NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_album_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_album_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"backup_selection\" INTEGER NOT NULL, \"is_ios_shared_album\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_ios_shared_album\" IN (0, 1)), \"linked_remote_album_id\" TEXT NULL REFERENCES remote_album_entity (id) ON DELETE SET NULL, \"marker\" INTEGER NULL CHECK (\"marker\" IN (0, 1)), PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_album_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_album_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES local_asset_entity (id) ON DELETE CASCADE, \"album_id\" TEXT NOT NULL REFERENCES local_album_entity (id) ON DELETE CASCADE, \"marker\" INTEGER NULL CHECK (\"marker\" IN (0, 1)), PRIMARY KEY (\"asset_id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_album_asset_album_asset",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_album_owner_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_owner_id ON remote_album_entity (owner_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_asset_cloud_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_stack_primary_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_owner_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)"
+ }
+ ]
+ },
+ {
+ "name": "UQ_remote_assets_owner_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)"
+ }
+ ]
+ },
+ {
+ "name": "UQ_remote_assets_owner_library_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_stack_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_local_date_time_day",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_day ON remote_asset_entity (STRFTIME('%Y-%m-%d', local_date_time))"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_local_date_time_month",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_month ON remote_asset_entity (STRFTIME('%Y-%m', local_date_time))"
+ }
+ ]
+ },
+ {
+ "name": "auth_user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"auth_user_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"email\" TEXT NOT NULL, \"is_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_admin\" IN (0, 1)), \"has_profile_image\" INTEGER NOT NULL DEFAULT 0 CHECK (\"has_profile_image\" IN (0, 1)), \"profile_changed_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"avatar_color\" INTEGER NOT NULL, \"quota_size_in_bytes\" INTEGER NOT NULL DEFAULT 0, \"quota_usage_in_bytes\" INTEGER NOT NULL DEFAULT 0, \"pin_code\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "user_metadata_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"user_metadata_entity\" (\"user_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"key\" INTEGER NOT NULL, \"value\" BLOB NOT NULL, PRIMARY KEY (\"user_id\", \"key\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "partner_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"partner_entity\" (\"shared_by_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"shared_with_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"in_timeline\" INTEGER NOT NULL DEFAULT 0 CHECK (\"in_timeline\" IN (0, 1)), PRIMARY KEY (\"shared_by_id\", \"shared_with_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_exif_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_exif_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"city\" TEXT NULL, \"state\" TEXT NULL, \"country\" TEXT NULL, \"date_time_original\" TEXT NULL, \"description\" TEXT NULL, \"height\" INTEGER NULL, \"width\" INTEGER NULL, \"exposure_time\" TEXT NULL, \"f_number\" REAL NULL, \"file_size\" INTEGER NULL, \"focal_length\" REAL NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, \"iso\" INTEGER NULL, \"make\" TEXT NULL, \"model\" TEXT NULL, \"lens\" TEXT NULL, \"orientation\" TEXT NULL, \"time_zone\" TEXT NULL, \"rating\" INTEGER NULL, \"projection_type\" TEXT NULL, PRIMARY KEY (\"asset_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"album_id\" TEXT NOT NULL REFERENCES remote_album_entity (id) ON DELETE CASCADE, PRIMARY KEY (\"asset_id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_user_entity\" (\"album_id\" TEXT NOT NULL REFERENCES remote_album_entity (id) ON DELETE CASCADE, \"user_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"role\" INTEGER NOT NULL, PRIMARY KEY (\"album_id\", \"user_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_asset_cloud_id_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_asset_cloud_id_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"cloud_id\" TEXT NULL, \"created_at\" TEXT NULL, \"adjustment_time\" TEXT NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, PRIMARY KEY (\"asset_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "memory_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"memory_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"deleted_at\" TEXT NULL, \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"type\" INTEGER NOT NULL, \"data\" TEXT NOT NULL, \"is_saved\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_saved\" IN (0, 1)), \"memory_at\" TEXT NOT NULL, \"seen_at\" TEXT NULL, \"show_at\" TEXT NULL, \"hide_at\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "memory_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"memory_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"memory_id\" TEXT NOT NULL REFERENCES memory_entity (id) ON DELETE CASCADE, PRIMARY KEY (\"asset_id\", \"memory_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "person_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"person_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"name\" TEXT NOT NULL, \"face_asset_id\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL CHECK (\"is_favorite\" IN (0, 1)), \"is_hidden\" INTEGER NOT NULL CHECK (\"is_hidden\" IN (0, 1)), \"color\" TEXT NULL, \"birth_date\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "asset_face_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"asset_face_entity\" (\"id\" TEXT NOT NULL, \"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"person_id\" TEXT NULL REFERENCES person_entity (id) ON DELETE SET NULL, \"image_width\" INTEGER NOT NULL, \"image_height\" INTEGER NOT NULL, \"bounding_box_x1\" INTEGER NOT NULL, \"bounding_box_y1\" INTEGER NOT NULL, \"bounding_box_x2\" INTEGER NOT NULL, \"bounding_box_y2\" INTEGER NOT NULL, \"source_type\" TEXT NOT NULL, \"is_visible\" INTEGER NOT NULL DEFAULT 1 CHECK (\"is_visible\" IN (0, 1)), \"deleted_at\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "store_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"store_entity\" (\"id\" INTEGER NOT NULL, \"string_value\" TEXT NULL, \"int_value\" INTEGER NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "trashed_local_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"trashed_local_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"album_id\" TEXT NOT NULL, \"checksum\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"orientation\" INTEGER NOT NULL DEFAULT 0, \"source\" INTEGER NOT NULL, \"playback_style\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "asset_edit_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"asset_edit_entity\" (\"id\" TEXT NOT NULL, \"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"action\" INTEGER NOT NULL, \"parameters\" BLOB NOT NULL, \"sequence\" INTEGER NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "idx_partner_shared_with_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_lat_lng",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_album_asset_album_asset",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_cloud_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_person_owner_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_face_person_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_face_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_trashed_local_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_trashed_local_asset_album",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_edit_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/mobile/drift_schemas/main/drift_schema_v24.json b/mobile/drift_schemas/main/drift_schema_v24.json
new file mode 100644
index 0000000000..94c65bd09a
--- /dev/null
+++ b/mobile/drift_schemas/main/drift_schema_v24.json
@@ -0,0 +1,3301 @@
+{
+ "_meta": {
+ "description": "This file contains a serialized version of schema entities for drift.",
+ "version": "1.3.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": "email",
+ "getter_name": "email",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "has_profile_image",
+ "getter_name": "hasProfileImage",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"has_profile_image\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"has_profile_image\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "profile_changed_at",
+ "getter_name": "profileChangedAt",
+ "moor_type": "dateTime",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('CURRENT_TIMESTAMP')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "avatar_color",
+ "getter_name": "avatarColor",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AvatarColor.values)",
+ "dart_type_name": "AvatarColor"
+ }
+ }
+ ],
+ "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_ms",
+ "getter_name": "durationMs",
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": []
+ },
+ {
+ "name": "library_id",
+ "getter_name": "libraryId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_edited",
+ "getter_name": "isEdited",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_edited\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_edited\" 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": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 2,
+ "references": [
+ 0
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "primary_asset_id",
+ "getter_name": "primaryAssetId",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 3,
+ "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_ms",
+ "getter_name": "durationMs",
+ "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": []
+ },
+ {
+ "name": "i_cloud_id",
+ "getter_name": "iCloudId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "adjustment_time",
+ "getter_name": "adjustmentTime",
+ "moor_type": "dateTime",
+ "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": "playback_style",
+ "getter_name": "playbackStyle",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetPlaybackStyle.values)",
+ "dart_type_name": "AssetPlaybackStyle"
+ }
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 4,
+ "references": [
+ 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": "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "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": 5,
+ "references": [
+ 4
+ ],
+ "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": "linked_remote_album_id",
+ "getter_name": "linkedRemoteAlbumId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "defaultConstraints": "REFERENCES remote_album_entity (id) ON DELETE SET NULL",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "REFERENCES remote_album_entity (id) ON DELETE SET NULL"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "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": 6,
+ "references": [
+ 3,
+ 5
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "local_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "local_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ "asset_id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 7,
+ "references": [
+ 6
+ ],
+ "type": "index",
+ "data": {
+ "on": 6,
+ "name": "idx_local_album_asset_album_asset",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 8,
+ "references": [
+ 3
+ ],
+ "type": "index",
+ "data": {
+ "on": 3,
+ "name": "idx_local_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 9,
+ "references": [
+ 3
+ ],
+ "type": "index",
+ "data": {
+ "on": 3,
+ "name": "idx_local_asset_cloud_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 10,
+ "references": [
+ 2
+ ],
+ "type": "index",
+ "data": {
+ "on": 2,
+ "name": "idx_stack_primary_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 11,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_owner_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 12,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "UQ_remote_assets_owner_checksum",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum\nON remote_asset_entity (owner_id, checksum)\nWHERE (library_id IS NULL);\n",
+ "unique": true,
+ "columns": []
+ }
+ },
+ {
+ "id": 13,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "UQ_remote_assets_owner_library_checksum",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum\nON remote_asset_entity (owner_id, library_id, checksum)\nWHERE (library_id IS NOT NULL);\n",
+ "unique": true,
+ "columns": []
+ }
+ },
+ {
+ "id": 14,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 15,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_stack_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 16,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_local_date_time_day",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_day ON remote_asset_entity (STRFTIME('%Y-%m-%d', local_date_time))",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 17,
+ "references": [
+ 1
+ ],
+ "type": "index",
+ "data": {
+ "on": 1,
+ "name": "idx_remote_asset_local_date_time_month",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_month ON remote_asset_entity (STRFTIME('%Y-%m', local_date_time))",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 18,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "auth_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": "email",
+ "getter_name": "email",
+ "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": "has_profile_image",
+ "getter_name": "hasProfileImage",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"has_profile_image\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"has_profile_image\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "profile_changed_at",
+ "getter_name": "profileChangedAt",
+ "moor_type": "dateTime",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('CURRENT_TIMESTAMP')",
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "avatar_color",
+ "getter_name": "avatarColor",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AvatarColor.values)",
+ "dart_type_name": "AvatarColor"
+ }
+ },
+ {
+ "name": "quota_size_in_bytes",
+ "getter_name": "quotaSizeInBytes",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "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": []
+ },
+ {
+ "name": "pin_code",
+ "getter_name": "pinCode",
+ "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": 19,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 20,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 21,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 22,
+ "references": [
+ 1,
+ 4
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 23,
+ "references": [
+ 4,
+ 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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_album_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 24,
+ "references": [
+ 1
+ ],
+ "type": "table",
+ "data": {
+ "name": "remote_asset_cloud_id_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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "cloud_id",
+ "getter_name": "cloudId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "created_at",
+ "getter_name": "createdAt",
+ "moor_type": "dateTime",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "adjustment_time",
+ "getter_name": "adjustmentTime",
+ "moor_type": "dateTime",
+ "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": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id"
+ ]
+ }
+ },
+ {
+ "id": 25,
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": 26,
+ "references": [
+ 1,
+ 25
+ ],
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "memory_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "asset_id",
+ "memory_id"
+ ]
+ }
+ },
+ {
+ "id": 27,
+ "references": [
+ 0
+ ],
+ "type": "table",
+ "data": {
+ "name": "person_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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "user_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "name",
+ "getter_name": "name",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "face_asset_id",
+ "getter_name": "faceAssetId",
+ "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": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_hidden",
+ "getter_name": "isHidden",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_hidden\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_hidden\" IN (0, 1))"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "color",
+ "getter_name": "color",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "birth_date",
+ "getter_name": "birthDate",
+ "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": 28,
+ "references": [
+ 1,
+ 27
+ ],
+ "type": "table",
+ "data": {
+ "name": "asset_face_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": "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "person_id",
+ "getter_name": "personId",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "defaultConstraints": "REFERENCES person_entity (id) ON DELETE SET NULL",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "REFERENCES person_entity (id) ON DELETE SET NULL"
+ },
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "person_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "setNull"
+ }
+ }
+ ]
+ },
+ {
+ "name": "image_width",
+ "getter_name": "imageWidth",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "image_height",
+ "getter_name": "imageHeight",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_x1",
+ "getter_name": "boundingBoxX1",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_y1",
+ "getter_name": "boundingBoxY1",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_x2",
+ "getter_name": "boundingBoxX2",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "bounding_box_y2",
+ "getter_name": "boundingBoxY2",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "source_type",
+ "getter_name": "sourceType",
+ "moor_type": "string",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "is_visible",
+ "getter_name": "isVisible",
+ "moor_type": "bool",
+ "nullable": false,
+ "customConstraints": null,
+ "defaultConstraints": "CHECK (\"is_visible\" IN (0, 1))",
+ "dialectAwareDefaultConstraints": {
+ "sqlite": "CHECK (\"is_visible\" IN (0, 1))"
+ },
+ "default_dart": "const CustomExpression('1')",
+ "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": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 29,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "store_entity",
+ "was_declared_in_moor": false,
+ "columns": [
+ {
+ "name": "id",
+ "getter_name": "id",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "string_value",
+ "getter_name": "stringValue",
+ "moor_type": "string",
+ "nullable": true,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ },
+ {
+ "name": "int_value",
+ "getter_name": "intValue",
+ "moor_type": "int",
+ "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": 30,
+ "references": [],
+ "type": "table",
+ "data": {
+ "name": "trashed_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_ms",
+ "getter_name": "durationMs",
+ "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": "album_id",
+ "getter_name": "albumId",
+ "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": []
+ },
+ {
+ "name": "source",
+ "getter_name": "source",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(TrashOrigin.values)",
+ "dart_type_name": "TrashOrigin"
+ }
+ },
+ {
+ "name": "playback_style",
+ "getter_name": "playbackStyle",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": "const CustomExpression('0')",
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetPlaybackStyle.values)",
+ "dart_type_name": "AssetPlaybackStyle"
+ }
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id",
+ "album_id"
+ ]
+ }
+ },
+ {
+ "id": 31,
+ "references": [
+ 1
+ ],
+ "type": "table",
+ "data": {
+ "name": "asset_edit_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": "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": [
+ {
+ "foreign_key": {
+ "to": {
+ "table": "remote_asset_entity",
+ "column": "id"
+ },
+ "initially_deferred": false,
+ "on_update": null,
+ "on_delete": "cascade"
+ }
+ }
+ ]
+ },
+ {
+ "name": "action",
+ "getter_name": "action",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "const EnumIndexConverter(AssetEditAction.values)",
+ "dart_type_name": "AssetEditAction"
+ }
+ },
+ {
+ "name": "parameters",
+ "getter_name": "parameters",
+ "moor_type": "blob",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": [],
+ "type_converter": {
+ "dart_expr": "editParameterConverter",
+ "dart_type_name": "Map"
+ }
+ },
+ {
+ "name": "sequence",
+ "getter_name": "sequence",
+ "moor_type": "int",
+ "nullable": false,
+ "customConstraints": null,
+ "default_dart": null,
+ "default_client_dart": null,
+ "dsl_features": []
+ }
+ ],
+ "is_virtual": false,
+ "without_rowid": true,
+ "constraints": [],
+ "strict": true,
+ "explicit_pk": [
+ "id"
+ ]
+ }
+ },
+ {
+ "id": 32,
+ "references": [
+ 20
+ ],
+ "type": "index",
+ "data": {
+ "on": 20,
+ "name": "idx_partner_shared_with_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 33,
+ "references": [
+ 21
+ ],
+ "type": "index",
+ "data": {
+ "on": 21,
+ "name": "idx_lat_lng",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 34,
+ "references": [
+ 22
+ ],
+ "type": "index",
+ "data": {
+ "on": 22,
+ "name": "idx_remote_album_asset_album_asset",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 35,
+ "references": [
+ 24
+ ],
+ "type": "index",
+ "data": {
+ "on": 24,
+ "name": "idx_remote_asset_cloud_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 36,
+ "references": [
+ 27
+ ],
+ "type": "index",
+ "data": {
+ "on": 27,
+ "name": "idx_person_owner_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 37,
+ "references": [
+ 28
+ ],
+ "type": "index",
+ "data": {
+ "on": 28,
+ "name": "idx_asset_face_person_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 38,
+ "references": [
+ 28
+ ],
+ "type": "index",
+ "data": {
+ "on": 28,
+ "name": "idx_asset_face_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 39,
+ "references": [
+ 30
+ ],
+ "type": "index",
+ "data": {
+ "on": 30,
+ "name": "idx_trashed_local_asset_checksum",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 40,
+ "references": [
+ 30
+ ],
+ "type": "index",
+ "data": {
+ "on": 30,
+ "name": "idx_trashed_local_asset_album",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)",
+ "unique": false,
+ "columns": []
+ }
+ },
+ {
+ "id": 41,
+ "references": [
+ 31
+ ],
+ "type": "index",
+ "data": {
+ "on": 31,
+ "name": "idx_asset_edit_asset_id",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)",
+ "unique": false,
+ "columns": []
+ }
+ }
+ ],
+ "fixed_sql": [
+ {
+ "name": "user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"user_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"email\" TEXT NOT NULL, \"has_profile_image\" INTEGER NOT NULL DEFAULT 0 CHECK (\"has_profile_image\" IN (0, 1)), \"profile_changed_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"avatar_color\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"checksum\" TEXT NOT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"local_date_time\" TEXT NULL, \"thumb_hash\" TEXT NULL, \"deleted_at\" TEXT NULL, \"live_photo_video_id\" TEXT NULL, \"visibility\" INTEGER NOT NULL, \"stack_id\" TEXT NULL, \"library_id\" TEXT NULL, \"is_edited\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_edited\" IN (0, 1)), PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "stack_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"stack_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"primary_asset_id\" TEXT NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"checksum\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"orientation\" INTEGER NOT NULL DEFAULT 0, \"i_cloud_id\" TEXT NULL, \"adjustment_time\" TEXT NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, \"playback_style\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"description\" TEXT NOT NULL DEFAULT '', \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"thumbnail_asset_id\" TEXT NULL REFERENCES remote_asset_entity (id) ON DELETE SET NULL, \"is_activity_enabled\" INTEGER NOT NULL DEFAULT 1 CHECK (\"is_activity_enabled\" IN (0, 1)), \"order\" INTEGER NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_album_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_album_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"backup_selection\" INTEGER NOT NULL, \"is_ios_shared_album\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_ios_shared_album\" IN (0, 1)), \"linked_remote_album_id\" TEXT NULL REFERENCES remote_album_entity (id) ON DELETE SET NULL, \"marker\" INTEGER NULL CHECK (\"marker\" IN (0, 1)), PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "local_album_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"local_album_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES local_asset_entity (id) ON DELETE CASCADE, \"album_id\" TEXT NOT NULL REFERENCES local_album_entity (id) ON DELETE CASCADE, \"marker\" INTEGER NULL CHECK (\"marker\" IN (0, 1)), PRIMARY KEY (\"asset_id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_album_asset_album_asset",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_local_asset_cloud_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_stack_primary_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_owner_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_checksum ON remote_asset_entity (owner_id, checksum)"
+ }
+ ]
+ },
+ {
+ "name": "UQ_remote_assets_owner_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)"
+ }
+ ]
+ },
+ {
+ "name": "UQ_remote_assets_owner_library_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_stack_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_local_date_time_day",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_day ON remote_asset_entity (STRFTIME('%Y-%m-%d', local_date_time))"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_local_date_time_month",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_local_date_time_month ON remote_asset_entity (STRFTIME('%Y-%m', local_date_time))"
+ }
+ ]
+ },
+ {
+ "name": "auth_user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"auth_user_entity\" (\"id\" TEXT NOT NULL, \"name\" TEXT NOT NULL, \"email\" TEXT NOT NULL, \"is_admin\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_admin\" IN (0, 1)), \"has_profile_image\" INTEGER NOT NULL DEFAULT 0 CHECK (\"has_profile_image\" IN (0, 1)), \"profile_changed_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"avatar_color\" INTEGER NOT NULL, \"quota_size_in_bytes\" INTEGER NOT NULL DEFAULT 0, \"quota_usage_in_bytes\" INTEGER NOT NULL DEFAULT 0, \"pin_code\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "user_metadata_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"user_metadata_entity\" (\"user_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"key\" INTEGER NOT NULL, \"value\" BLOB NOT NULL, PRIMARY KEY (\"user_id\", \"key\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "partner_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"partner_entity\" (\"shared_by_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"shared_with_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"in_timeline\" INTEGER NOT NULL DEFAULT 0 CHECK (\"in_timeline\" IN (0, 1)), PRIMARY KEY (\"shared_by_id\", \"shared_with_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_exif_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_exif_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"city\" TEXT NULL, \"state\" TEXT NULL, \"country\" TEXT NULL, \"date_time_original\" TEXT NULL, \"description\" TEXT NULL, \"height\" INTEGER NULL, \"width\" INTEGER NULL, \"exposure_time\" TEXT NULL, \"f_number\" REAL NULL, \"file_size\" INTEGER NULL, \"focal_length\" REAL NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, \"iso\" INTEGER NULL, \"make\" TEXT NULL, \"model\" TEXT NULL, \"lens\" TEXT NULL, \"orientation\" TEXT NULL, \"time_zone\" TEXT NULL, \"rating\" INTEGER NULL, \"projection_type\" TEXT NULL, PRIMARY KEY (\"asset_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"album_id\" TEXT NOT NULL REFERENCES remote_album_entity (id) ON DELETE CASCADE, PRIMARY KEY (\"asset_id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_album_user_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_album_user_entity\" (\"album_id\" TEXT NOT NULL REFERENCES remote_album_entity (id) ON DELETE CASCADE, \"user_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"role\" INTEGER NOT NULL, PRIMARY KEY (\"album_id\", \"user_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "remote_asset_cloud_id_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"remote_asset_cloud_id_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"cloud_id\" TEXT NULL, \"created_at\" TEXT NULL, \"adjustment_time\" TEXT NULL, \"latitude\" REAL NULL, \"longitude\" REAL NULL, PRIMARY KEY (\"asset_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "memory_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"memory_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"deleted_at\" TEXT NULL, \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"type\" INTEGER NOT NULL, \"data\" TEXT NOT NULL, \"is_saved\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_saved\" IN (0, 1)), \"memory_at\" TEXT NOT NULL, \"seen_at\" TEXT NULL, \"show_at\" TEXT NULL, \"hide_at\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "memory_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"memory_asset_entity\" (\"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"memory_id\" TEXT NOT NULL REFERENCES memory_entity (id) ON DELETE CASCADE, PRIMARY KEY (\"asset_id\", \"memory_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "person_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"person_entity\" (\"id\" TEXT NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"owner_id\" TEXT NOT NULL REFERENCES user_entity (id) ON DELETE CASCADE, \"name\" TEXT NOT NULL, \"face_asset_id\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL CHECK (\"is_favorite\" IN (0, 1)), \"is_hidden\" INTEGER NOT NULL CHECK (\"is_hidden\" IN (0, 1)), \"color\" TEXT NULL, \"birth_date\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "asset_face_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"asset_face_entity\" (\"id\" TEXT NOT NULL, \"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"person_id\" TEXT NULL REFERENCES person_entity (id) ON DELETE SET NULL, \"image_width\" INTEGER NOT NULL, \"image_height\" INTEGER NOT NULL, \"bounding_box_x1\" INTEGER NOT NULL, \"bounding_box_y1\" INTEGER NOT NULL, \"bounding_box_x2\" INTEGER NOT NULL, \"bounding_box_y2\" INTEGER NOT NULL, \"source_type\" TEXT NOT NULL, \"is_visible\" INTEGER NOT NULL DEFAULT 1 CHECK (\"is_visible\" IN (0, 1)), \"deleted_at\" TEXT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "store_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"store_entity\" (\"id\" INTEGER NOT NULL, \"string_value\" TEXT NULL, \"int_value\" INTEGER NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "trashed_local_asset_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"trashed_local_asset_entity\" (\"name\" TEXT NOT NULL, \"type\" INTEGER NOT NULL, \"created_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"updated_at\" TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), \"width\" INTEGER NULL, \"height\" INTEGER NULL, \"duration_ms\" INTEGER NULL, \"id\" TEXT NOT NULL, \"album_id\" TEXT NOT NULL, \"checksum\" TEXT NULL, \"is_favorite\" INTEGER NOT NULL DEFAULT 0 CHECK (\"is_favorite\" IN (0, 1)), \"orientation\" INTEGER NOT NULL DEFAULT 0, \"source\" INTEGER NOT NULL, \"playback_style\" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (\"id\", \"album_id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "asset_edit_entity",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE TABLE IF NOT EXISTS \"asset_edit_entity\" (\"id\" TEXT NOT NULL, \"asset_id\" TEXT NOT NULL REFERENCES remote_asset_entity (id) ON DELETE CASCADE, \"action\" INTEGER NOT NULL, \"parameters\" BLOB NOT NULL, \"sequence\" INTEGER NOT NULL, PRIMARY KEY (\"id\")) WITHOUT ROWID, STRICT;"
+ }
+ ]
+ },
+ {
+ "name": "idx_partner_shared_with_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_lat_lng",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_album_asset_album_asset",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_remote_asset_cloud_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_person_owner_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_face_person_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_face_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_trashed_local_asset_checksum",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)"
+ }
+ ]
+ },
+ {
+ "name": "idx_trashed_local_asset_album",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)"
+ }
+ ]
+ },
+ {
+ "name": "idx_asset_edit_asset_id",
+ "sql": [
+ {
+ "dialect": "sqlite",
+ "sql": "CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock
index c0d7e2c35a..c566d37182 100644
--- a/mobile/ios/Podfile.lock
+++ b/mobile/ios/Podfile.lock
@@ -20,19 +20,21 @@ PODS:
- Flutter
- flutter_udid (0.0.1):
- Flutter
- - SAMKeychain
- - flutter_web_auth_2 (3.0.0):
+ - KeychainAccess
+ - flutter_web_auth_2 (5.0.0):
- Flutter
- fluttertoast (0.0.2):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
+ - FlutterMacOS
- home_widget (0.0.1):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
- integration_test (0.0.1):
- Flutter
+ - KeychainAccess (4.2.2)
- local_auth_darwin (0.0.1):
- Flutter
- FlutterMacOS
@@ -44,19 +46,13 @@ PODS:
- Flutter
- network_info_plus (0.0.1):
- Flutter
- - objective_c (0.0.1):
- - Flutter
- package_info_plus (0.4.5):
- Flutter
- - path_provider_foundation (0.0.1):
- - Flutter
- - FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- - photo_manager (3.7.1):
+ - photo_manager (3.9.0):
- Flutter
- FlutterMacOS
- - SAMKeychain (1.5.3)
- share_handler_ios (0.0.14):
- Flutter
- share_handler_ios/share_handler_ios_models (= 0.0.14)
@@ -70,28 +66,6 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- - sqflite_darwin (0.0.4):
- - Flutter
- - FlutterMacOS
- - sqlite3 (3.49.2):
- - sqlite3/common (= 3.49.2)
- - sqlite3/common (3.49.2)
- - sqlite3/dbstatvtab (3.49.2):
- - sqlite3/common
- - sqlite3/fts5 (3.49.2):
- - sqlite3/common
- - sqlite3/perf-threadsafe (3.49.2):
- - sqlite3/common
- - sqlite3/rtree (3.49.2):
- - sqlite3/common
- - sqlite3_flutter_libs (0.0.1):
- - Flutter
- - FlutterMacOS
- - sqlite3 (~> 3.49.1)
- - sqlite3/dbstatvtab
- - sqlite3/fts5
- - sqlite3/perf-threadsafe
- - sqlite3/rtree
- url_launcher_ios (0.0.1):
- Flutter
- wakelock_plus (0.0.1):
@@ -110,7 +84,7 @@ DEPENDENCIES:
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
- flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
+ - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
@@ -118,25 +92,20 @@ DEPENDENCIES:
- maplibre_gl (from `.symlinks/plugins/maplibre_gl/ios`)
- native_video_player (from `.symlinks/plugins/native_video_player/ios`)
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
- - objective_c (from `.symlinks/plugins/objective_c/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- - photo_manager (from `.symlinks/plugins/photo_manager/ios`)
+ - photo_manager (from `.symlinks/plugins/photo_manager/darwin`)
- share_handler_ios (from `.symlinks/plugins/share_handler_ios/ios`)
- share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
trunk:
+ - KeychainAccess
- MapLibre
- - SAMKeychain
- - sqlite3
EXTERNAL SOURCES:
background_downloader:
@@ -164,7 +133,7 @@ EXTERNAL SOURCES:
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
geolocator_apple:
- :path: ".symlinks/plugins/geolocator_apple/ios"
+ :path: ".symlinks/plugins/geolocator_apple/darwin"
home_widget:
:path: ".symlinks/plugins/home_widget/ios"
image_picker_ios:
@@ -179,16 +148,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/native_video_player/ios"
network_info_plus:
:path: ".symlinks/plugins/network_info_plus/ios"
- objective_c:
- :path: ".symlinks/plugins/objective_c/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
- path_provider_foundation:
- :path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
photo_manager:
- :path: ".symlinks/plugins/photo_manager/ios"
+ :path: ".symlinks/plugins/photo_manager/darwin"
share_handler_ios:
:path: ".symlinks/plugins/share_handler_ios/ios"
share_handler_ios_models:
@@ -197,10 +162,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
- sqflite_darwin:
- :path: ".symlinks/plugins/sqflite_darwin/darwin"
- sqlite3_flutter_libs:
- :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
wakelock_plus:
@@ -216,32 +177,27 @@ SPEC CHECKSUMS:
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
- flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
- flutter_web_auth_2: 5c8d9dcd7848b5a9efb086d24e7a9adcae979c80
+ flutter_udid: 92a5d31fe0526b7b6002a2318df702e12e7eb300
+ flutter_web_auth_2: 646fc9df97a01c59e5eea99b237da2c6360f8439
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
- geolocator_apple: 1560c3c875af2a412242c7a923e15d0d401966ff
+ geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
- local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
+ KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
+ local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
MapLibre: 69e572367f4ef6287e18246cfafc39c80cdcabcd
maplibre_gl: 3c924e44725147b03dda33430ad216005b40555f
native_video_player: b65c58951ede2f93d103a25366bdebca95081265
network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc
- objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
- path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
- photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
- SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
+ photo_manager: 25fd77df14f4f0ba5ef99e2c61814dde77e2bceb
share_handler_ios: e2244e990f826b2c8eaa291ac3831569438ba0fb
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
- shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
- sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
- sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1
- sqlite3_flutter_libs: f8fc13346870e73fe35ebf6dbb997fbcd156b241
- url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
+ shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
+ url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
PODFILE CHECKSUM: 938abbae4114b9c2140c550a2a0d8f7c674f5dfe
diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj
index f88d624b89..fbffa69ba5 100644
--- a/mobile/ios/Runner.xcodeproj/project.pbxproj
+++ b/mobile/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 77;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -751,7 +751,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -760,7 +760,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.121.0;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.profile;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.profile;
PRODUCT_NAME = "Immich-Profile";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -895,7 +895,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -904,7 +904,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.121.0;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.vdebug;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.debug;
PRODUCT_NAME = "Immich-Debug";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -925,7 +925,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -958,7 +958,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -975,7 +975,7 @@
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.vdebug.Widget;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.debug.Widget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
@@ -1001,7 +1001,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -1041,7 +1041,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -1057,7 +1057,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.profile.Widget;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.profile.Widget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1081,7 +1081,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -1098,7 +1098,7 @@
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.vdebug.ShareExtension;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.debug.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@@ -1125,7 +1125,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -1166,7 +1166,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
- DEVELOPMENT_TEAM = 2F67MQ8R79;
+ DEVELOPMENT_TEAM = 2W7AC6T8T5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
@@ -1182,7 +1182,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = app.alextran.immich.profile.ShareExtension;
+ PRODUCT_BUNDLE_IDENTIFIER = app.futo.immich.profile.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
diff --git a/mobile/ios/Runner/AppDelegate.swift b/mobile/ios/Runner/AppDelegate.swift
index 627e1575eb..216146a6f3 100644
--- a/mobile/ios/Runner/AppDelegate.swift
+++ b/mobile/ios/Runner/AppDelegate.swift
@@ -1,12 +1,4 @@
-import BackgroundTasks
-import Flutter
import native_video_player
-import network_info_plus
-import path_provider_foundation
-import permission_handler_apple
-import photo_manager
-import shared_preferences_foundation
-import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
diff --git a/mobile/ios/Runner/Background/BackgroundWorker.g.swift b/mobile/ios/Runner/Background/BackgroundWorker.g.swift
index 8c9391e8d2..40553441a6 100644
--- a/mobile/ios/Runner/Background/BackgroundWorker.g.swift
+++ b/mobile/ios/Runner/Background/BackgroundWorker.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -32,7 +32,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
@@ -50,6 +50,19 @@ private func nilOrValue(_ value: Any?) -> T? {
return value as! T?
}
+private func doubleEqualsBackgroundWorker(_ lhs: Double, _ rhs: Double) -> Bool {
+ return (lhs.isNaN && rhs.isNaN) || lhs == rhs
+}
+
+private func doubleHashBackgroundWorker(_ value: Double, _ hasher: inout Hasher) {
+ if value.isNaN {
+ hasher.combine(0x7FF8000000000000)
+ } else {
+ // Normalize -0.0 to 0.0
+ hasher.combine(value == 0 ? 0 : value)
+ }
+}
+
func deepEqualsBackgroundWorker(_ lhs: Any?, _ rhs: Any?) -> Bool {
let cleanLhs = nilOrValue(lhs) as Any?
let cleanRhs = nilOrValue(rhs) as Any?
@@ -60,59 +73,92 @@ func deepEqualsBackgroundWorker(_ lhs: Any?, _ rhs: Any?) -> Bool {
case (nil, _), (_, nil):
return false
+ case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs:
+ return true
+
case is (Void, Void):
return true
- case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable):
- return cleanLhsHashable == cleanRhsHashable
-
- case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]):
- guard cleanLhsArray.count == cleanRhsArray.count else { return false }
- for (index, element) in cleanLhsArray.enumerated() {
- if !deepEqualsBackgroundWorker(element, cleanRhsArray[index]) {
+ case (let lhsArray, let rhsArray) as ([Any?], [Any?]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !deepEqualsBackgroundWorker(element, rhsArray[index]) {
return false
}
}
return true
- case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
- guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false }
- for (key, cleanLhsValue) in cleanLhsDictionary {
- guard cleanRhsDictionary.index(forKey: key) != nil else { return false }
- if !deepEqualsBackgroundWorker(cleanLhsValue, cleanRhsDictionary[key]!) {
+ case (let lhsArray, let rhsArray) as ([Double], [Double]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !doubleEqualsBackgroundWorker(element, rhsArray[index]) {
return false
}
}
return true
+ case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
+ guard lhsDictionary.count == rhsDictionary.count else { return false }
+ for (lhsKey, lhsValue) in lhsDictionary {
+ var found = false
+ for (rhsKey, rhsValue) in rhsDictionary {
+ if deepEqualsBackgroundWorker(lhsKey, rhsKey) {
+ if deepEqualsBackgroundWorker(lhsValue, rhsValue) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if !found { return false }
+ }
+ return true
+
+ case (let lhs as Double, let rhs as Double):
+ return doubleEqualsBackgroundWorker(lhs, rhs)
+
+ case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable):
+ return lhsHashable == rhsHashable
+
default:
- // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue.
return false
}
}
func deepHashBackgroundWorker(value: Any?, hasher: inout Hasher) {
- if let valueList = value as? [AnyHashable] {
- for item in valueList { deepHashBackgroundWorker(value: item, hasher: &hasher) }
- return
- }
-
- if let valueDict = value as? [AnyHashable: AnyHashable] {
- for key in valueDict.keys {
- hasher.combine(key)
- deepHashBackgroundWorker(value: valueDict[key]!, hasher: &hasher)
+ let cleanValue = nilOrValue(value) as Any?
+ if let cleanValue = cleanValue {
+ if let doubleValue = cleanValue as? Double {
+ doubleHashBackgroundWorker(doubleValue, &hasher)
+ } else if let valueList = cleanValue as? [Any?] {
+ for item in valueList {
+ deepHashBackgroundWorker(value: item, hasher: &hasher)
+ }
+ } else if let valueList = cleanValue as? [Double] {
+ for item in valueList {
+ doubleHashBackgroundWorker(item, &hasher)
+ }
+ } else if let valueDict = cleanValue as? [AnyHashable: Any?] {
+ var result = 0
+ for (key, value) in valueDict {
+ var entryKeyHasher = Hasher()
+ deepHashBackgroundWorker(value: key, hasher: &entryKeyHasher)
+ var entryValueHasher = Hasher()
+ deepHashBackgroundWorker(value: value, hasher: &entryValueHasher)
+ result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize())
+ }
+ hasher.combine(result)
+ } else if let hashableValue = cleanValue as? AnyHashable {
+ hasher.combine(hashableValue)
+ } else {
+ hasher.combine(String(describing: cleanValue))
}
- return
+ } else {
+ hasher.combine(0)
}
-
- if let hashableValue = value as? AnyHashable {
- hasher.combine(hashableValue.hashValue)
- }
-
- return hasher.combine(String(describing: value))
}
-
/// Generated class from Pigeon that represents data sent in messages.
struct BackgroundWorkerSettings: Hashable {
@@ -137,9 +183,16 @@ struct BackgroundWorkerSettings: Hashable {
]
}
static func == (lhs: BackgroundWorkerSettings, rhs: BackgroundWorkerSettings) -> Bool {
- return deepEqualsBackgroundWorker(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsBackgroundWorker(lhs.requiresCharging, rhs.requiresCharging) && deepEqualsBackgroundWorker(lhs.minimumDelaySeconds, rhs.minimumDelaySeconds)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashBackgroundWorker(value: toList(), hasher: &hasher)
+ hasher.combine("BackgroundWorkerSettings")
+ deepHashBackgroundWorker(value: requiresCharging, hasher: &hasher)
+ deepHashBackgroundWorker(value: minimumDelaySeconds, hasher: &hasher)
}
}
diff --git a/mobile/ios/Runner/Connectivity/Connectivity.g.swift b/mobile/ios/Runner/Connectivity/Connectivity.g.swift
index f8d85a2edf..c7aff63e10 100644
--- a/mobile/ios/Runner/Connectivity/Connectivity.g.swift
+++ b/mobile/ios/Runner/Connectivity/Connectivity.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -32,7 +32,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
diff --git a/mobile/ios/Runner/Core/Network.g.swift b/mobile/ios/Runner/Core/Network.g.swift
index 5a8075f91a..7d9b9f14be 100644
--- a/mobile/ios/Runner/Core/Network.g.swift
+++ b/mobile/ios/Runner/Core/Network.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -32,7 +32,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
@@ -46,6 +46,19 @@ private func nilOrValue(_ value: Any?) -> T? {
return value as! T?
}
+private func doubleEqualsNetwork(_ lhs: Double, _ rhs: Double) -> Bool {
+ return (lhs.isNaN && rhs.isNaN) || lhs == rhs
+}
+
+private func doubleHashNetwork(_ value: Double, _ hasher: inout Hasher) {
+ if value.isNaN {
+ hasher.combine(0x7FF8000000000000)
+ } else {
+ // Normalize -0.0 to 0.0
+ hasher.combine(value == 0 ? 0 : value)
+ }
+}
+
func deepEqualsNetwork(_ lhs: Any?, _ rhs: Any?) -> Bool {
let cleanLhs = nilOrValue(lhs) as Any?
let cleanRhs = nilOrValue(rhs) as Any?
@@ -56,59 +69,92 @@ func deepEqualsNetwork(_ lhs: Any?, _ rhs: Any?) -> Bool {
case (nil, _), (_, nil):
return false
+ case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs:
+ return true
+
case is (Void, Void):
return true
- case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable):
- return cleanLhsHashable == cleanRhsHashable
-
- case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]):
- guard cleanLhsArray.count == cleanRhsArray.count else { return false }
- for (index, element) in cleanLhsArray.enumerated() {
- if !deepEqualsNetwork(element, cleanRhsArray[index]) {
+ case (let lhsArray, let rhsArray) as ([Any?], [Any?]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !deepEqualsNetwork(element, rhsArray[index]) {
return false
}
}
return true
- case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
- guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false }
- for (key, cleanLhsValue) in cleanLhsDictionary {
- guard cleanRhsDictionary.index(forKey: key) != nil else { return false }
- if !deepEqualsNetwork(cleanLhsValue, cleanRhsDictionary[key]!) {
+ case (let lhsArray, let rhsArray) as ([Double], [Double]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !doubleEqualsNetwork(element, rhsArray[index]) {
return false
}
}
return true
+ case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
+ guard lhsDictionary.count == rhsDictionary.count else { return false }
+ for (lhsKey, lhsValue) in lhsDictionary {
+ var found = false
+ for (rhsKey, rhsValue) in rhsDictionary {
+ if deepEqualsNetwork(lhsKey, rhsKey) {
+ if deepEqualsNetwork(lhsValue, rhsValue) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if !found { return false }
+ }
+ return true
+
+ case (let lhs as Double, let rhs as Double):
+ return doubleEqualsNetwork(lhs, rhs)
+
+ case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable):
+ return lhsHashable == rhsHashable
+
default:
- // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue.
return false
}
}
func deepHashNetwork(value: Any?, hasher: inout Hasher) {
- if let valueList = value as? [AnyHashable] {
- for item in valueList { deepHashNetwork(value: item, hasher: &hasher) }
- return
- }
-
- if let valueDict = value as? [AnyHashable: AnyHashable] {
- for key in valueDict.keys {
- hasher.combine(key)
- deepHashNetwork(value: valueDict[key]!, hasher: &hasher)
+ let cleanValue = nilOrValue(value) as Any?
+ if let cleanValue = cleanValue {
+ if let doubleValue = cleanValue as? Double {
+ doubleHashNetwork(doubleValue, &hasher)
+ } else if let valueList = cleanValue as? [Any?] {
+ for item in valueList {
+ deepHashNetwork(value: item, hasher: &hasher)
+ }
+ } else if let valueList = cleanValue as? [Double] {
+ for item in valueList {
+ doubleHashNetwork(item, &hasher)
+ }
+ } else if let valueDict = cleanValue as? [AnyHashable: Any?] {
+ var result = 0
+ for (key, value) in valueDict {
+ var entryKeyHasher = Hasher()
+ deepHashNetwork(value: key, hasher: &entryKeyHasher)
+ var entryValueHasher = Hasher()
+ deepHashNetwork(value: value, hasher: &entryValueHasher)
+ result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize())
+ }
+ hasher.combine(result)
+ } else if let hashableValue = cleanValue as? AnyHashable {
+ hasher.combine(hashableValue)
+ } else {
+ hasher.combine(String(describing: cleanValue))
}
- return
+ } else {
+ hasher.combine(0)
}
-
- if let hashableValue = value as? AnyHashable {
- hasher.combine(hashableValue.hashValue)
- }
-
- return hasher.combine(String(describing: value))
}
-
/// Generated class from Pigeon that represents data sent in messages.
struct ClientCertData: Hashable {
@@ -133,9 +179,16 @@ struct ClientCertData: Hashable {
]
}
static func == (lhs: ClientCertData, rhs: ClientCertData) -> Bool {
- return deepEqualsNetwork(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsNetwork(lhs.data, rhs.data) && deepEqualsNetwork(lhs.password, rhs.password)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashNetwork(value: toList(), hasher: &hasher)
+ hasher.combine("ClientCertData")
+ deepHashNetwork(value: data, hasher: &hasher)
+ deepHashNetwork(value: password, hasher: &hasher)
}
}
@@ -170,9 +223,18 @@ struct ClientCertPrompt: Hashable {
]
}
static func == (lhs: ClientCertPrompt, rhs: ClientCertPrompt) -> Bool {
- return deepEqualsNetwork(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsNetwork(lhs.title, rhs.title) && deepEqualsNetwork(lhs.message, rhs.message) && deepEqualsNetwork(lhs.cancel, rhs.cancel) && deepEqualsNetwork(lhs.confirm, rhs.confirm)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashNetwork(value: toList(), hasher: &hasher)
+ hasher.combine("ClientCertPrompt")
+ deepHashNetwork(value: title, hasher: &hasher)
+ deepHashNetwork(value: message, hasher: &hasher)
+ deepHashNetwork(value: cancel, hasher: &hasher)
+ deepHashNetwork(value: confirm, hasher: &hasher)
}
}
diff --git a/mobile/ios/Runner/Images/LocalImages.g.swift b/mobile/ios/Runner/Images/LocalImages.g.swift
index 146950cd51..b9324260be 100644
--- a/mobile/ios/Runner/Images/LocalImages.g.swift
+++ b/mobile/ios/Runner/Images/LocalImages.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -32,7 +32,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
diff --git a/mobile/ios/Runner/Images/RemoteImages.g.swift b/mobile/ios/Runner/Images/RemoteImages.g.swift
index 9fcffd4233..12eaaeec60 100644
--- a/mobile/ios/Runner/Images/RemoteImages.g.swift
+++ b/mobile/ios/Runner/Images/RemoteImages.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -32,7 +32,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist
index a37b46b5bc..3b030e4f86 100644
--- a/mobile/ios/Runner/Info.plist
+++ b/mobile/ios/Runner/Info.plist
@@ -150,6 +150,27 @@
INSendMessageIntent
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneClassName
+ UIWindowScene
+ UISceneConfigurationName
+ flutter
+ UISceneDelegateClassName
+ FlutterSceneDelegate
+ UISceneStoryboardFile
+ Main
+
+
+
+
UIApplicationSupportsIndirectInputEvents
UIBackgroundModes
@@ -176,27 +197,6 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
- UIApplicationSceneManifest
-
- UIApplicationSupportsMultipleScenes
-
- UISceneConfigurations
-
- UIWindowSceneSessionRoleApplication
-
-
- UISceneClassName
- UIWindowScene
- UISceneDelegateClassName
- FlutterSceneDelegate
- UISceneConfigurationName
- flutter
- UISceneStoryboardFile
- Main
-
-
-
-
UIViewControllerBasedStatusBarAppearance
io.flutter.embedded_views_preview
diff --git a/mobile/ios/Runner/Sync/Messages.g.swift b/mobile/ios/Runner/Sync/Messages.g.swift
index 6bba25d94b..2933fc89af 100644
--- a/mobile/ios/Runner/Sync/Messages.g.swift
+++ b/mobile/ios/Runner/Sync/Messages.g.swift
@@ -1,4 +1,4 @@
-// Autogenerated from Pigeon (v26.0.2), do not edit directly.
+// Autogenerated from Pigeon (v26.3.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@@ -50,7 +50,7 @@ private func wrapError(_ error: Any) -> [Any?] {
}
return [
"\(error)",
- "\(type(of: error))",
+ "\(Swift.type(of: error))",
"Stacktrace: \(Thread.callStackSymbols)",
]
}
@@ -64,6 +64,19 @@ private func nilOrValue(_ value: Any?) -> T? {
return value as! T?
}
+private func doubleEqualsMessages(_ lhs: Double, _ rhs: Double) -> Bool {
+ return (lhs.isNaN && rhs.isNaN) || lhs == rhs
+}
+
+private func doubleHashMessages(_ value: Double, _ hasher: inout Hasher) {
+ if value.isNaN {
+ hasher.combine(0x7FF8000000000000)
+ } else {
+ // Normalize -0.0 to 0.0
+ hasher.combine(value == 0 ? 0 : value)
+ }
+}
+
func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool {
let cleanLhs = nilOrValue(lhs) as Any?
let cleanRhs = nilOrValue(rhs) as Any?
@@ -74,59 +87,92 @@ func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool {
case (nil, _), (_, nil):
return false
+ case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs:
+ return true
+
case is (Void, Void):
return true
- case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable):
- return cleanLhsHashable == cleanRhsHashable
-
- case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]):
- guard cleanLhsArray.count == cleanRhsArray.count else { return false }
- for (index, element) in cleanLhsArray.enumerated() {
- if !deepEqualsMessages(element, cleanRhsArray[index]) {
+ case (let lhsArray, let rhsArray) as ([Any?], [Any?]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !deepEqualsMessages(element, rhsArray[index]) {
return false
}
}
return true
- case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
- guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false }
- for (key, cleanLhsValue) in cleanLhsDictionary {
- guard cleanRhsDictionary.index(forKey: key) != nil else { return false }
- if !deepEqualsMessages(cleanLhsValue, cleanRhsDictionary[key]!) {
+ case (let lhsArray, let rhsArray) as ([Double], [Double]):
+ guard lhsArray.count == rhsArray.count else { return false }
+ for (index, element) in lhsArray.enumerated() {
+ if !doubleEqualsMessages(element, rhsArray[index]) {
return false
}
}
return true
+ case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]):
+ guard lhsDictionary.count == rhsDictionary.count else { return false }
+ for (lhsKey, lhsValue) in lhsDictionary {
+ var found = false
+ for (rhsKey, rhsValue) in rhsDictionary {
+ if deepEqualsMessages(lhsKey, rhsKey) {
+ if deepEqualsMessages(lhsValue, rhsValue) {
+ found = true
+ break
+ } else {
+ return false
+ }
+ }
+ }
+ if !found { return false }
+ }
+ return true
+
+ case (let lhs as Double, let rhs as Double):
+ return doubleEqualsMessages(lhs, rhs)
+
+ case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable):
+ return lhsHashable == rhsHashable
+
default:
- // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue.
return false
}
}
func deepHashMessages(value: Any?, hasher: inout Hasher) {
- if let valueList = value as? [AnyHashable] {
- for item in valueList { deepHashMessages(value: item, hasher: &hasher) }
- return
- }
-
- if let valueDict = value as? [AnyHashable: AnyHashable] {
- for key in valueDict.keys {
- hasher.combine(key)
- deepHashMessages(value: valueDict[key]!, hasher: &hasher)
+ let cleanValue = nilOrValue(value) as Any?
+ if let cleanValue = cleanValue {
+ if let doubleValue = cleanValue as? Double {
+ doubleHashMessages(doubleValue, &hasher)
+ } else if let valueList = cleanValue as? [Any?] {
+ for item in valueList {
+ deepHashMessages(value: item, hasher: &hasher)
+ }
+ } else if let valueList = cleanValue as? [Double] {
+ for item in valueList {
+ doubleHashMessages(item, &hasher)
+ }
+ } else if let valueDict = cleanValue as? [AnyHashable: Any?] {
+ var result = 0
+ for (key, value) in valueDict {
+ var entryKeyHasher = Hasher()
+ deepHashMessages(value: key, hasher: &entryKeyHasher)
+ var entryValueHasher = Hasher()
+ deepHashMessages(value: value, hasher: &entryValueHasher)
+ result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize())
+ }
+ hasher.combine(result)
+ } else if let hashableValue = cleanValue as? AnyHashable {
+ hasher.combine(hashableValue)
+ } else {
+ hasher.combine(String(describing: cleanValue))
}
- return
+ } else {
+ hasher.combine(0)
}
-
- if let hashableValue = value as? AnyHashable {
- hasher.combine(hashableValue.hashValue)
- }
-
- return hasher.combine(String(describing: value))
}
-
enum PlatformAssetPlaybackStyle: Int {
case unknown = 0
@@ -146,7 +192,7 @@ struct PlatformAsset: Hashable {
var updatedAt: Int64? = nil
var width: Int64? = nil
var height: Int64? = nil
- var durationInSeconds: Int64
+ var durationMs: Int64
var orientation: Int64
var isFavorite: Bool
var adjustmentTime: Int64? = nil
@@ -164,7 +210,7 @@ struct PlatformAsset: Hashable {
let updatedAt: Int64? = nilOrValue(pigeonVar_list[4])
let width: Int64? = nilOrValue(pigeonVar_list[5])
let height: Int64? = nilOrValue(pigeonVar_list[6])
- let durationInSeconds = pigeonVar_list[7] as! Int64
+ let durationMs = pigeonVar_list[7] as! Int64
let orientation = pigeonVar_list[8] as! Int64
let isFavorite = pigeonVar_list[9] as! Bool
let adjustmentTime: Int64? = nilOrValue(pigeonVar_list[10])
@@ -180,7 +226,7 @@ struct PlatformAsset: Hashable {
updatedAt: updatedAt,
width: width,
height: height,
- durationInSeconds: durationInSeconds,
+ durationMs: durationMs,
orientation: orientation,
isFavorite: isFavorite,
adjustmentTime: adjustmentTime,
@@ -198,7 +244,7 @@ struct PlatformAsset: Hashable {
updatedAt,
width,
height,
- durationInSeconds,
+ durationMs,
orientation,
isFavorite,
adjustmentTime,
@@ -208,9 +254,28 @@ struct PlatformAsset: Hashable {
]
}
static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool {
- return deepEqualsMessages(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsMessages(lhs.id, rhs.id) && deepEqualsMessages(lhs.name, rhs.name) && deepEqualsMessages(lhs.type, rhs.type) && deepEqualsMessages(lhs.createdAt, rhs.createdAt) && deepEqualsMessages(lhs.updatedAt, rhs.updatedAt) && deepEqualsMessages(lhs.width, rhs.width) && deepEqualsMessages(lhs.height, rhs.height) && deepEqualsMessages(lhs.durationMs, rhs.durationMs) && deepEqualsMessages(lhs.orientation, rhs.orientation) && deepEqualsMessages(lhs.isFavorite, rhs.isFavorite) && deepEqualsMessages(lhs.adjustmentTime, rhs.adjustmentTime) && deepEqualsMessages(lhs.latitude, rhs.latitude) && deepEqualsMessages(lhs.longitude, rhs.longitude) && deepEqualsMessages(lhs.playbackStyle, rhs.playbackStyle)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashMessages(value: toList(), hasher: &hasher)
+ hasher.combine("PlatformAsset")
+ deepHashMessages(value: id, hasher: &hasher)
+ deepHashMessages(value: name, hasher: &hasher)
+ deepHashMessages(value: type, hasher: &hasher)
+ deepHashMessages(value: createdAt, hasher: &hasher)
+ deepHashMessages(value: updatedAt, hasher: &hasher)
+ deepHashMessages(value: width, hasher: &hasher)
+ deepHashMessages(value: height, hasher: &hasher)
+ deepHashMessages(value: durationMs, hasher: &hasher)
+ deepHashMessages(value: orientation, hasher: &hasher)
+ deepHashMessages(value: isFavorite, hasher: &hasher)
+ deepHashMessages(value: adjustmentTime, hasher: &hasher)
+ deepHashMessages(value: latitude, hasher: &hasher)
+ deepHashMessages(value: longitude, hasher: &hasher)
+ deepHashMessages(value: playbackStyle, hasher: &hasher)
}
}
@@ -249,9 +314,19 @@ struct PlatformAlbum: Hashable {
]
}
static func == (lhs: PlatformAlbum, rhs: PlatformAlbum) -> Bool {
- return deepEqualsMessages(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsMessages(lhs.id, rhs.id) && deepEqualsMessages(lhs.name, rhs.name) && deepEqualsMessages(lhs.updatedAt, rhs.updatedAt) && deepEqualsMessages(lhs.isCloud, rhs.isCloud) && deepEqualsMessages(lhs.assetCount, rhs.assetCount)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashMessages(value: toList(), hasher: &hasher)
+ hasher.combine("PlatformAlbum")
+ deepHashMessages(value: id, hasher: &hasher)
+ deepHashMessages(value: name, hasher: &hasher)
+ deepHashMessages(value: updatedAt, hasher: &hasher)
+ deepHashMessages(value: isCloud, hasher: &hasher)
+ deepHashMessages(value: assetCount, hasher: &hasher)
}
}
@@ -286,9 +361,18 @@ struct SyncDelta: Hashable {
]
}
static func == (lhs: SyncDelta, rhs: SyncDelta) -> Bool {
- return deepEqualsMessages(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsMessages(lhs.hasChanges, rhs.hasChanges) && deepEqualsMessages(lhs.updates, rhs.updates) && deepEqualsMessages(lhs.deletes, rhs.deletes) && deepEqualsMessages(lhs.assetAlbums, rhs.assetAlbums)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashMessages(value: toList(), hasher: &hasher)
+ hasher.combine("SyncDelta")
+ deepHashMessages(value: hasChanges, hasher: &hasher)
+ deepHashMessages(value: updates, hasher: &hasher)
+ deepHashMessages(value: deletes, hasher: &hasher)
+ deepHashMessages(value: assetAlbums, hasher: &hasher)
}
}
@@ -319,9 +403,17 @@ struct HashResult: Hashable {
]
}
static func == (lhs: HashResult, rhs: HashResult) -> Bool {
- return deepEqualsMessages(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsMessages(lhs.assetId, rhs.assetId) && deepEqualsMessages(lhs.error, rhs.error) && deepEqualsMessages(lhs.hash, rhs.hash)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashMessages(value: toList(), hasher: &hasher)
+ hasher.combine("HashResult")
+ deepHashMessages(value: assetId, hasher: &hasher)
+ deepHashMessages(value: error, hasher: &hasher)
+ deepHashMessages(value: hash, hasher: &hasher)
}
}
@@ -352,9 +444,17 @@ struct CloudIdResult: Hashable {
]
}
static func == (lhs: CloudIdResult, rhs: CloudIdResult) -> Bool {
- return deepEqualsMessages(lhs.toList(), rhs.toList()) }
+ if Swift.type(of: lhs) != Swift.type(of: rhs) {
+ return false
+ }
+ return deepEqualsMessages(lhs.assetId, rhs.assetId) && deepEqualsMessages(lhs.error, rhs.error) && deepEqualsMessages(lhs.cloudId, rhs.cloudId)
+ }
+
func hash(into hasher: inout Hasher) {
- deepHashMessages(value: toList(), hasher: &hasher)
+ hasher.combine("CloudIdResult")
+ deepHashMessages(value: assetId, hasher: &hasher)
+ deepHashMessages(value: error, hasher: &hasher)
+ deepHashMessages(value: cloudId, hasher: &hasher)
}
}
diff --git a/mobile/ios/Runner/Sync/MessagesImpl.swift b/mobile/ios/Runner/Sync/MessagesImpl.swift
index 8022fb06d2..ec96729d8f 100644
--- a/mobile/ios/Runner/Sync/MessagesImpl.swift
+++ b/mobile/ios/Runner/Sync/MessagesImpl.swift
@@ -171,7 +171,7 @@ class NativeSyncApiImpl: ImmichPlugin, NativeSyncApi, FlutterPlugin {
id: asset.localIdentifier,
name: "",
type: 0,
- durationInSeconds: 0,
+ durationMs: 0,
orientation: 0,
isFavorite: false,
playbackStyle: .unknown
diff --git a/mobile/ios/Runner/Sync/PHAssetExtensions.swift b/mobile/ios/Runner/Sync/PHAssetExtensions.swift
index 0fc1dfc701..d4d947d5bb 100644
--- a/mobile/ios/Runner/Sync/PHAssetExtensions.swift
+++ b/mobile/ios/Runner/Sync/PHAssetExtensions.swift
@@ -21,7 +21,7 @@ extension PHAsset {
updatedAt: modificationDate.map { Int64($0.timeIntervalSince1970) },
width: Int64(pixelWidth),
height: Int64(pixelHeight),
- durationInSeconds: Int64(duration),
+ durationMs: Int64(duration * 1000),
orientation: 0,
isFavorite: isFavorite,
adjustmentTime: adjustmentTimestamp,
diff --git a/mobile/ios/ShareExtension/Info.plist b/mobile/ios/ShareExtension/Info.plist
index 0f52fbffdf..dbed75e380 100644
--- a/mobile/ios/ShareExtension/Info.plist
+++ b/mobile/ios/ShareExtension/Info.plist
@@ -1,35 +1,35 @@
-
- AppGroupId
- $(CUSTOM_GROUP_ID)
- NSExtension
-
- NSExtensionAttributes
-
- IntentsSupported
-
- INSendMessageIntent
-
- NSExtensionActivationRule
- SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments,
+
+ AppGroupId
+ $(CUSTOM_GROUP_ID)
+ NSExtension
+
+ NSExtensionAttributes
+
+ IntentsSupported
+
+ INSendMessageIntent
+
+ NSExtensionActivationRule
+ SUBQUERY ( extensionItems, $extensionItem, SUBQUERY ( $extensionItem.attachments,
$attachment, ( ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url"
|| ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image" || ANY
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text" || ANY
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie" || ANY
$attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ) ).@count > 0
).@count > 0
- PHSupportedMediaTypes
-
- Video
- Image
-
-
- NSExtensionMainStoryboard
- MainInterface
- NSExtensionPointIdentifier
- com.apple.share-services
-
-
-
\ No newline at end of file
+ PHSupportedMediaTypes
+
+ Video
+ Image
+
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.share-services
+
+
+
diff --git a/mobile/ios/ShareExtension/ShareExtension.entitlements b/mobile/ios/ShareExtension/ShareExtension.entitlements
index 4ad1a257d8..d16dcca065 100644
--- a/mobile/ios/ShareExtension/ShareExtension.entitlements
+++ b/mobile/ios/ShareExtension/ShareExtension.entitlements
@@ -1,10 +1,10 @@
-
- com.apple.security.application-groups
-
- group.app.immich.share
-
-
-
+
+ com.apple.security.application-groups
+
+ group.app.immich.share
+
+
+
\ No newline at end of file
diff --git a/mobile/ios/WidgetExtension/WidgetExtension.entitlements b/mobile/ios/WidgetExtension/WidgetExtension.entitlements
index 4ad1a257d8..d16dcca065 100644
--- a/mobile/ios/WidgetExtension/WidgetExtension.entitlements
+++ b/mobile/ios/WidgetExtension/WidgetExtension.entitlements
@@ -1,10 +1,10 @@
-
- com.apple.security.application-groups
-
- group.app.immich.share
-
-
-
+
+ com.apple.security.application-groups
+
+ group.app.immich.share
+
+
+
\ No newline at end of file
diff --git a/mobile/lib/domain/models/album/album.model.dart b/mobile/lib/domain/models/album/album.model.dart
index 4558e1d5be..ef67d729ec 100644
--- a/mobile/lib/domain/models/album/album.model.dart
+++ b/mobile/lib/domain/models/album/album.model.dart
@@ -8,6 +8,7 @@ enum AlbumUserRole {
// do not change this order!
editor,
viewer,
+ owner,
}
// Model for an album stored in the server
diff --git a/mobile/lib/domain/models/asset/base_asset.model.dart b/mobile/lib/domain/models/asset/base_asset.model.dart
index 85c42fd24f..15f705c65b 100644
--- a/mobile/lib/domain/models/asset/base_asset.model.dart
+++ b/mobile/lib/domain/models/asset/base_asset.model.dart
@@ -25,7 +25,7 @@ sealed class BaseAsset {
final DateTime updatedAt;
final int? width;
final int? height;
- final int? durationInSeconds;
+ final int? durationMs;
final bool isFavorite;
final String? livePhotoVideoId;
final bool isEdited;
@@ -38,7 +38,7 @@ sealed class BaseAsset {
required this.updatedAt,
this.width,
this.height,
- this.durationInSeconds,
+ this.durationMs,
this.isFavorite = false,
this.livePhotoVideoId,
required this.isEdited,
@@ -53,15 +53,17 @@ sealed class BaseAsset {
AssetPlaybackStyle get playbackStyle {
if (isVideo) return AssetPlaybackStyle.video;
if (isMotionPhoto) return AssetPlaybackStyle.livePhoto;
- if (isImage && durationInSeconds != null && durationInSeconds! > 0) return AssetPlaybackStyle.imageAnimated;
+ if (isImage && durationMs != null && durationMs! > 0) {
+ return AssetPlaybackStyle.imageAnimated;
+ }
if (isImage) return AssetPlaybackStyle.image;
return AssetPlaybackStyle.unknown;
}
Duration get duration {
- final durationInSeconds = this.durationInSeconds;
- if (durationInSeconds != null) {
- return Duration(seconds: durationInSeconds);
+ final durationMs = this.durationMs;
+ if (durationMs != null) {
+ return Duration(milliseconds: durationMs);
}
return const Duration();
}
@@ -88,7 +90,7 @@ sealed class BaseAsset {
updatedAt: $updatedAt,
width: ${width ?? ""},
height: ${height ?? ""},
- durationInSeconds: ${durationInSeconds ?? ""},
+ durationMs: ${durationMs ?? ""},
isFavorite: $isFavorite,
isEdited: $isEdited,
}''';
@@ -104,7 +106,7 @@ sealed class BaseAsset {
updatedAt == other.updatedAt &&
width == other.width &&
height == other.height &&
- durationInSeconds == other.durationInSeconds &&
+ durationMs == other.durationMs &&
isFavorite == other.isFavorite &&
isEdited == other.isEdited;
}
@@ -119,7 +121,7 @@ sealed class BaseAsset {
updatedAt.hashCode ^
width.hashCode ^
height.hashCode ^
- durationInSeconds.hashCode ^
+ durationMs.hashCode ^
isFavorite.hashCode ^
isEdited.hashCode;
}
diff --git a/mobile/lib/domain/models/asset/local_asset.model.dart b/mobile/lib/domain/models/asset/local_asset.model.dart
index 6766f4c3a2..04aa6cd846 100644
--- a/mobile/lib/domain/models/asset/local_asset.model.dart
+++ b/mobile/lib/domain/models/asset/local_asset.model.dart
@@ -23,7 +23,7 @@ class LocalAsset extends BaseAsset {
required super.updatedAt,
super.width,
super.height,
- super.durationInSeconds,
+ super.durationMs,
super.isFavorite = false,
super.livePhotoVideoId,
this.orientation = 0,
@@ -58,7 +58,7 @@ class LocalAsset extends BaseAsset {
updatedAt: $updatedAt,
width: ${width ?? ""},
height: ${height ?? ""},
- durationInSeconds: ${durationInSeconds ?? ""},
+ durationMs: ${durationMs ?? ""},
playbackStyle: $playbackStyle,
remoteId: ${remoteId ?? ""},
cloudId: ${cloudId ?? ""},
@@ -108,7 +108,7 @@ class LocalAsset extends BaseAsset {
DateTime? updatedAt,
int? width,
int? height,
- int? durationInSeconds,
+ int? durationMs,
bool? isFavorite,
int? orientation,
AssetPlaybackStyle? playbackStyle,
@@ -128,7 +128,7 @@ class LocalAsset extends BaseAsset {
updatedAt: updatedAt ?? this.updatedAt,
width: width ?? this.width,
height: height ?? this.height,
- durationInSeconds: durationInSeconds ?? this.durationInSeconds,
+ durationMs: durationMs ?? this.durationMs,
isFavorite: isFavorite ?? this.isFavorite,
orientation: orientation ?? this.orientation,
playbackStyle: playbackStyle ?? this.playbackStyle,
diff --git a/mobile/lib/domain/models/asset/remote_asset.model.dart b/mobile/lib/domain/models/asset/remote_asset.model.dart
index 745e8f46ff..36dc6242e1 100644
--- a/mobile/lib/domain/models/asset/remote_asset.model.dart
+++ b/mobile/lib/domain/models/asset/remote_asset.model.dart
@@ -22,7 +22,7 @@ class RemoteAsset extends BaseAsset {
required super.updatedAt,
super.width,
super.height,
- super.durationInSeconds,
+ super.durationMs,
super.isFavorite = false,
this.thumbHash,
this.visibility = AssetVisibility.timeline,
@@ -57,7 +57,7 @@ class RemoteAsset extends BaseAsset {
updatedAt: $updatedAt,
width: ${width ?? ""},
height: ${height ?? ""},
- durationInSeconds: ${durationInSeconds ?? ""},
+ durationMs: ${durationMs ?? ""},
localId: ${localId ?? ""},
isFavorite: $isFavorite,
thumbHash: ${thumbHash ?? ""},
@@ -102,7 +102,7 @@ class RemoteAsset extends BaseAsset {
DateTime? updatedAt,
int? width,
int? height,
- int? durationInSeconds,
+ int? durationMs,
bool? isFavorite,
String? thumbHash,
AssetVisibility? visibility,
@@ -121,7 +121,7 @@ class RemoteAsset extends BaseAsset {
updatedAt: updatedAt ?? this.updatedAt,
width: width ?? this.width,
height: height ?? this.height,
- durationInSeconds: durationInSeconds ?? this.durationInSeconds,
+ durationMs: durationMs ?? this.durationMs,
isFavorite: isFavorite ?? this.isFavorite,
thumbHash: thumbHash ?? this.thumbHash,
visibility: visibility ?? this.visibility,
@@ -146,7 +146,7 @@ class RemoteAssetExif extends RemoteAsset {
required super.updatedAt,
super.width,
super.height,
- super.durationInSeconds,
+ super.durationMs,
super.isFavorite = false,
super.thumbHash,
super.visibility = AssetVisibility.timeline,
@@ -178,7 +178,7 @@ class RemoteAssetExif extends RemoteAsset {
DateTime? updatedAt,
int? width,
int? height,
- int? durationInSeconds,
+ int? durationMs,
bool? isFavorite,
String? thumbHash,
AssetVisibility? visibility,
@@ -198,7 +198,7 @@ class RemoteAssetExif extends RemoteAsset {
updatedAt: updatedAt ?? this.updatedAt,
width: width ?? this.width,
height: height ?? this.height,
- durationInSeconds: durationInSeconds ?? this.durationInSeconds,
+ durationMs: durationMs ?? this.durationMs,
isFavorite: isFavorite ?? this.isFavorite,
thumbHash: thumbHash ?? this.thumbHash,
visibility: visibility ?? this.visibility,
diff --git a/mobile/lib/domain/models/exif.model.dart b/mobile/lib/domain/models/exif.model.dart
index 45b787d586..97c0ba3823 100644
--- a/mobile/lib/domain/models/exif.model.dart
+++ b/mobile/lib/domain/models/exif.model.dart
@@ -29,7 +29,7 @@ class ExifInfo {
bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
String get exposureTime {
- if (exposureSeconds == null) {
+ if (exposureSeconds == null || exposureSeconds! <= 0 || exposureSeconds!.isNaN) {
return "";
}
if (exposureSeconds! < 1) {
diff --git a/mobile/lib/domain/services/local_sync.service.dart b/mobile/lib/domain/services/local_sync.service.dart
index 029482978a..1d9ab1e490 100644
--- a/mobile/lib/domain/services/local_sync.service.dart
+++ b/mobile/lib/domain/services/local_sync.service.dart
@@ -337,7 +337,7 @@ class LocalSyncService {
a.createdAt.isAtSameMomentAs(b.createdAt) &&
a.width == b.width &&
a.height == b.height &&
- a.durationInSeconds == b.durationInSeconds;
+ a.durationMs == b.durationMs;
}
final firstAdjustment = a.adjustmentTime?.millisecondsSinceEpoch ?? 0;
@@ -346,7 +346,7 @@ class LocalSyncService {
a.createdAt.isAtSameMomentAs(b.createdAt) &&
a.width == b.width &&
a.height == b.height &&
- a.durationInSeconds == b.durationInSeconds &&
+ a.durationMs == b.durationMs &&
a.latitude == b.latitude &&
a.longitude == b.longitude;
}
@@ -432,7 +432,7 @@ extension PlatformToLocalAsset on PlatformAsset {
updatedAt: tryFromSecondsSinceEpoch(updatedAt, isUtc: true) ?? DateTime.timestamp(),
width: width,
height: height,
- durationInSeconds: durationInSeconds,
+ durationMs: durationMs,
isFavorite: isFavorite,
orientation: orientation,
playbackStyle: _toPlaybackStyle(playbackStyle),
diff --git a/mobile/lib/domain/services/remote_album.service.dart b/mobile/lib/domain/services/remote_album.service.dart
index 945ba8eb3f..f060ba9290 100644
--- a/mobile/lib/domain/services/remote_album.service.dart
+++ b/mobile/lib/domain/services/remote_album.service.dart
@@ -7,8 +7,8 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_album.repository.dart';
import 'package:immich_mobile/models/albums/album_search.model.dart';
-import 'package:immich_mobile/repositories/drift_album_api_repository.dart';
import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart';
+import 'package:immich_mobile/repositories/drift_album_api_repository.dart';
class RemoteAlbumService {
final DriftRemoteAlbumRepository _repository;
@@ -28,10 +28,6 @@ class RemoteAlbumService {
return _repository.get(albumId);
}
- Future getByName(String albumName, String ownerId) {
- return _repository.getByName(albumName, ownerId);
- }
-
Future> sortAlbums(
List albums,
AlbumSortMode sortMode, {
@@ -86,8 +82,18 @@ class RemoteAlbumService {
return filtered;
}
- Future createAlbum({required String title, required List assetIds, String? description}) async {
- final album = await _albumApiRepository.createDriftAlbum(title, description: description, assetIds: assetIds);
+ Future createAlbum({
+ required String title,
+ required UserDto owner,
+ required List assetIds,
+ String? description,
+ }) async {
+ final album = await _albumApiRepository.createDriftAlbum(
+ title,
+ owner,
+ description: description,
+ assetIds: assetIds,
+ );
await _repository.create(album, assetIds);
return album;
@@ -101,8 +107,10 @@ class RemoteAlbumService {
bool? isActivityEnabled,
AlbumAssetOrder? order,
}) async {
+ final owner = await _repository.getOwner(albumId);
final updatedAlbum = await _albumApiRepository.updateAlbum(
albumId,
+ owner,
name: name,
description: description,
thumbnailAssetId: thumbnailAssetId,
diff --git a/mobile/lib/domain/services/sync_linked_album.service.dart b/mobile/lib/domain/services/sync_linked_album.service.dart
index b61ca1c965..3bc76083b8 100644
--- a/mobile/lib/domain/services/sync_linked_album.service.dart
+++ b/mobile/lib/domain/services/sync_linked_album.service.dart
@@ -1,8 +1,11 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/domain/services/store.service.dart';
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_album.repository.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
+import 'package:immich_mobile/providers/infrastructure/store.provider.dart';
import 'package:immich_mobile/repositories/drift_album_api_repository.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:logging/logging.dart';
@@ -12,6 +15,7 @@ final syncLinkedAlbumServiceProvider = Provider(
ref.watch(localAlbumRepository),
ref.watch(remoteAlbumRepository),
ref.watch(driftAlbumApiRepositoryProvider),
+ ref.watch(storeServiceProvider),
),
);
@@ -19,8 +23,14 @@ class SyncLinkedAlbumService {
final DriftLocalAlbumRepository _localAlbumRepository;
final DriftRemoteAlbumRepository _remoteAlbumRepository;
final DriftAlbumApiRepository _albumApiRepository;
+ final StoreService _storeService;
- SyncLinkedAlbumService(this._localAlbumRepository, this._remoteAlbumRepository, this._albumApiRepository);
+ SyncLinkedAlbumService(
+ this._localAlbumRepository,
+ this._remoteAlbumRepository,
+ this._albumApiRepository,
+ this._storeService,
+ );
final _log = Logger("SyncLinkedAlbumService");
@@ -103,7 +113,11 @@ class SyncLinkedAlbumService {
/// Creates a new remote album and links it to the local album
Future _createAndLinkNewRemoteAlbum(LocalAlbum localAlbum) async {
dPrint(() => "Creating new remote album for local album: ${localAlbum.name}");
- final newRemoteAlbum = await _albumApiRepository.createDriftAlbum(localAlbum.name, assetIds: []);
+ final newRemoteAlbum = await _albumApiRepository.createDriftAlbum(
+ localAlbum.name,
+ _storeService.get(StoreKey.currentUser),
+ assetIds: [],
+ );
await _remoteAlbumRepository.create(newRemoteAlbum, []);
return _localAlbumRepository.linkRemoteAlbum(localAlbum.id, newRemoteAlbum.id);
}
diff --git a/mobile/lib/domain/services/sync_stream.service.dart b/mobile/lib/domain/services/sync_stream.service.dart
index 9769c2eeec..01772683f7 100644
--- a/mobile/lib/domain/services/sync_stream.service.dart
+++ b/mobile/lib/domain/services/sync_stream.service.dart
@@ -3,6 +3,7 @@
import 'dart:async';
import 'dart:convert';
+import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/sync_event.model.dart';
import 'package:immich_mobile/entities/store.entity.dart';
@@ -191,17 +192,22 @@ class SyncStreamService {
case SyncEntityType.assetV1:
final remoteSyncAssets = data.cast();
await _syncStreamRepository.updateAssetsV1(remoteSyncAssets);
- if (CurrentPlatform.isAndroid && Store.get(StoreKey.manageLocalMediaAndroid, false)) {
- final hasPermission = await _localFilesManager.hasManageMediaPermission();
- if (hasPermission) {
- await _handleRemoteTrashed(remoteSyncAssets.where((e) => e.deletedAt != null).map((e) => e.checksum));
+ await _runWithManageMediaPermission(
+ logContext: "Trashed Assets",
+ action: () async {
+ await _handleRemoteDeleted(remoteSyncAssets.where((e) => e.deletedAt != null).map((e) => e.id));
await _applyRemoteRestoreToLocal();
- } else {
- _logger.warning("sync Trashed Assets cannot proceed because MANAGE_MEDIA permission is missing");
- }
- }
+ },
+ );
return;
case SyncEntityType.assetDeleteV1:
+ await _runWithManageMediaPermission(
+ logContext: "Deleted Assets",
+ action: () async {
+ final remoteSyncAssets = data.cast();
+ await _handleRemoteDeleted(remoteSyncAssets.map((e) => e.assetId));
+ },
+ );
return _syncStreamRepository.deleteAssetsV1(data.cast());
case SyncEntityType.assetExifV1:
return _syncStreamRepository.updateAssetsExifV1(data.cast());
@@ -225,6 +231,8 @@ class SyncStreamService {
return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner backfill');
case SyncEntityType.albumV1:
return _syncStreamRepository.updateAlbumsV1(data.cast());
+ case SyncEntityType.albumV2:
+ return _syncStreamRepository.updateAlbumsV2(data.cast());
case SyncEntityType.albumDeleteV1:
return _syncStreamRepository.deleteAlbumsV1(data.cast());
case SyncEntityType.albumUserV1:
@@ -380,28 +388,32 @@ class SyncStreamService {
}
}
- Future _handleRemoteTrashed(Iterable checksums) async {
- if (checksums.isEmpty) {
+ Future _handleRemoteDeleted(Iterable remoteIds) async {
+ if (remoteIds.isEmpty) {
return Future.value();
} else {
- final localAssetsToTrash = await _localAssetRepository.getAssetsFromBackupAlbums(checksums);
+ final localAssetsToTrash = await _localAssetRepository.getAssetsFromBackupAlbums(remoteIds);
if (localAssetsToTrash.isNotEmpty) {
- final mediaUrls = await Future.wait(
- localAssetsToTrash.values
- .expand((e) => e)
- .map((localAsset) => _storageRepository.getAssetEntityForAsset(localAsset).then((e) => e?.getMediaUrl())),
- );
- _logger.info("Moving to trash ${mediaUrls.join(", ")} assets");
- final result = await _localFilesManager.moveToTrash(mediaUrls.nonNulls.toList());
- if (result) {
- await _trashedLocalAssetRepository.trashLocalAsset(localAssetsToTrash);
- }
+ await _trashLocalAssets(localAssetsToTrash);
} else {
- _logger.info("No assets found in backup-enabled albums for assets: $checksums");
+ _logger.info("No assets found in backup-enabled albums for remote assets: $remoteIds");
}
}
}
+ Future _trashLocalAssets(Map> localAssetsToTrash) async {
+ final mediaUrls = await Future.wait(
+ localAssetsToTrash.values
+ .expand((e) => e)
+ .map((localAsset) => _storageRepository.getAssetEntityForAsset(localAsset).then((e) => e?.getMediaUrl())),
+ );
+ _logger.info("Moving to trash ${mediaUrls.join(", ")} assets");
+ final result = await _localFilesManager.moveToTrash(mediaUrls.nonNulls.toList());
+ if (result) {
+ await _trashedLocalAssetRepository.trashLocalAsset(localAssetsToTrash);
+ }
+ }
+
Future _applyRemoteRestoreToLocal() async {
final assetsToRestore = await _trashedLocalAssetRepository.getToRestore();
if (assetsToRestore.isNotEmpty) {
@@ -411,4 +423,21 @@ class SyncStreamService {
_logger.info("No remote assets found for restoration");
}
}
+
+ Future _runWithManageMediaPermission({
+ required String logContext,
+ required Future Function() action,
+ }) async {
+ if (!CurrentPlatform.isAndroid || !Store.get(StoreKey.manageLocalMediaAndroid, false)) {
+ return;
+ }
+
+ final hasPermission = await _localFilesManager.hasManageMediaPermission();
+ if (!hasPermission) {
+ _logger.warning("sync $logContext cannot proceed because MANAGE_MEDIA permission is missing");
+ return;
+ }
+
+ await action();
+ }
}
diff --git a/mobile/lib/extensions/asset_extensions.dart b/mobile/lib/extensions/asset_extensions.dart
index 6e8101bd04..6bcc11f18d 100644
--- a/mobile/lib/extensions/asset_extensions.dart
+++ b/mobile/lib/extensions/asset_extensions.dart
@@ -14,7 +14,7 @@ extension DTOToAsset on api.AssetResponseDto {
updatedAt: updatedAt,
ownerId: ownerId,
visibility: visibility.toAssetVisibility(),
- durationInSeconds: duration?.toDuration()?.inSeconds ?? 0,
+ durationMs: duration?.toDuration()?.inMilliseconds ?? 0,
height: height?.toInt(),
width: width?.toInt(),
isFavorite: isFavorite,
@@ -36,7 +36,7 @@ extension DTOToAsset on api.AssetResponseDto {
updatedAt: updatedAt,
ownerId: ownerId,
visibility: visibility.toAssetVisibility(),
- durationInSeconds: duration?.toDuration()?.inSeconds ?? 0,
+ durationMs: duration?.toDuration()?.inMilliseconds ?? 0,
height: height?.toInt(),
width: width?.toInt(),
isFavorite: isFavorite,
diff --git a/mobile/lib/extensions/string_extensions.dart b/mobile/lib/extensions/string_extensions.dart
index ae31565044..d30c221f96 100644
--- a/mobile/lib/extensions/string_extensions.dart
+++ b/mobile/lib/extensions/string_extensions.dart
@@ -7,11 +7,16 @@ extension StringExtension on String {
}
extension DurationExtension on String {
- /// Parses and returns the string of format HH:MM:SS as a duration object else null
+ /// Parses and returns the string of format HH:MM:SS.ffffff as a duration object else null
Duration? toDuration() {
try {
- final parts = split(':').map((e) => double.parse(e).toInt()).toList(growable: false);
- return Duration(hours: parts[0], minutes: parts[1], seconds: parts[2]);
+ final parts = split(':');
+ final hours = double.parse(parts[0]).toInt();
+ final minutes = double.parse(parts[1]).toInt();
+ final secondsParts = parts[2].split('.');
+ final seconds = int.parse(secondsParts[0]);
+ final milliseconds = secondsParts.length > 1 ? (double.parse('0.${secondsParts[1]}') * 1000).round() : 0;
+ return Duration(hours: hours, minutes: minutes, seconds: seconds, milliseconds: milliseconds);
} catch (e) {
return null;
}
diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.dart b/mobile/lib/infrastructure/entities/local_asset.entity.dart
index e1cb5f5597..5a14a44fb7 100644
--- a/mobile/lib/infrastructure/entities/local_asset.entity.dart
+++ b/mobile/lib/infrastructure/entities/local_asset.entity.dart
@@ -39,7 +39,7 @@ extension LocalAssetEntityDataDomainExtension on LocalAssetEntityData {
type: type,
createdAt: createdAt,
updatedAt: updatedAt,
- durationInSeconds: durationInSeconds,
+ durationMs: durationMs,
isFavorite: isFavorite,
height: height,
width: width,
diff --git a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
index 92ac3d2e35..e01e6ce745 100644
--- a/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
+++ b/mobile/lib/infrastructure/entities/local_asset.entity.drift.dart
@@ -16,7 +16,7 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder =
i0.Value updatedAt,
i0.Value width,
i0.Value height,
- i0.Value durationInSeconds,
+ i0.Value durationMs,
required String id,
i0.Value checksum,
i0.Value isFavorite,
@@ -35,7 +35,7 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder =
i0.Value updatedAt,
i0.Value width,
i0.Value height,
- i0.Value durationInSeconds,
+ i0.Value durationMs,
i0.Value id,
i0.Value checksum,
i0.Value isFavorite,
@@ -87,8 +87,8 @@ class $$LocalAssetEntityTableFilterComposer
builder: (column) => i0.ColumnFilters(column),
);
- i0.ColumnFilters get durationInSeconds => $composableBuilder(
- column: $table.durationInSeconds,
+ i0.ColumnFilters get durationMs => $composableBuilder(
+ column: $table.durationMs,
builder: (column) => i0.ColumnFilters(column),
);
@@ -182,8 +182,8 @@ class $$LocalAssetEntityTableOrderingComposer
builder: (column) => i0.ColumnOrderings(column),
);
- i0.ColumnOrderings get durationInSeconds => $composableBuilder(
- column: $table.durationInSeconds,
+ i0.ColumnOrderings get durationMs => $composableBuilder(
+ column: $table.durationMs,
builder: (column) => i0.ColumnOrderings(column),
);
@@ -260,8 +260,8 @@ class $$LocalAssetEntityTableAnnotationComposer
i0.GeneratedColumn get height =>
$composableBuilder(column: $table.height, builder: (column) => column);
- i0.GeneratedColumn get durationInSeconds => $composableBuilder(
- column: $table.durationInSeconds,
+ i0.GeneratedColumn get durationMs => $composableBuilder(
+ column: $table.durationMs,
builder: (column) => column,
);
@@ -348,7 +348,7 @@ class $$LocalAssetEntityTableTableManager
i0.Value updatedAt = const i0.Value.absent(),
i0.Value width = const i0.Value.absent(),
i0.Value height = const i0.Value.absent(),
- i0.Value durationInSeconds = const i0.Value.absent(),
+ i0.Value durationMs = const i0.Value.absent(),
i0.Value id = const i0.Value.absent(),
i0.Value checksum = const i0.Value.absent(),
i0.Value isFavorite = const i0.Value.absent(),
@@ -366,7 +366,7 @@ class $$LocalAssetEntityTableTableManager
updatedAt: updatedAt,
width: width,
height: height,
- durationInSeconds: durationInSeconds,
+ durationMs: durationMs,
id: id,
checksum: checksum,
isFavorite: isFavorite,
@@ -385,7 +385,7 @@ class $$LocalAssetEntityTableTableManager
i0.Value updatedAt = const i0.Value.absent(),
i0.Value width = const i0.Value.absent(),
i0.Value height = const i0.Value.absent(),
- i0.Value durationInSeconds = const i0.Value.absent(),
+ i0.Value durationMs = const i0.Value.absent(),
required String id,
i0.Value checksum = const i0.Value.absent(),
i0.Value isFavorite = const i0.Value.absent(),
@@ -403,7 +403,7 @@ class $$LocalAssetEntityTableTableManager
updatedAt: updatedAt,
width: width,
height: height,
- durationInSeconds: durationInSeconds,
+ durationMs: durationMs,
id: id,
checksum: checksum,
isFavorite: isFavorite,
@@ -522,17 +522,17 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
type: i0.DriftSqlType.int,
requiredDuringInsert: false,
);
- static const i0.VerificationMeta _durationInSecondsMeta =
- const i0.VerificationMeta('durationInSeconds');
+ static const i0.VerificationMeta _durationMsMeta = const i0.VerificationMeta(
+ 'durationMs',
+ );
@override
- late final i0.GeneratedColumn durationInSeconds =
- i0.GeneratedColumn(
- 'duration_in_seconds',
- aliasedName,
- true,
- type: i0.DriftSqlType.int,
- requiredDuringInsert: false,
- );
+ late final i0.GeneratedColumn durationMs = i0.GeneratedColumn(
+ 'duration_ms',
+ aliasedName,
+ true,
+ type: i0.DriftSqlType.int,
+ requiredDuringInsert: false,
+ );
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
@override
late final i0.GeneratedColumn id = i0.GeneratedColumn(
@@ -645,7 +645,7 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
updatedAt,
width,
height,
- durationInSeconds,
+ durationMs,
id,
checksum,
isFavorite,
@@ -700,13 +700,10 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
height.isAcceptableOrUnknown(data['height']!, _heightMeta),
);
}
- if (data.containsKey('duration_in_seconds')) {
+ if (data.containsKey('duration_ms')) {
context.handle(
- _durationInSecondsMeta,
- durationInSeconds.isAcceptableOrUnknown(
- data['duration_in_seconds']!,
- _durationInSecondsMeta,
- ),
+ _durationMsMeta,
+ durationMs.isAcceptableOrUnknown(data['duration_ms']!, _durationMsMeta),
);
}
if (data.containsKey('id')) {
@@ -800,9 +797,9 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
i0.DriftSqlType.int,
data['${effectivePrefix}height'],
),
- durationInSeconds: attachedDatabase.typeMapping.read(
+ durationMs: attachedDatabase.typeMapping.read(
i0.DriftSqlType.int,
- data['${effectivePrefix}duration_in_seconds'],
+ data['${effectivePrefix}duration_ms'],
),
id: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string,
@@ -870,7 +867,7 @@ class LocalAssetEntityData extends i0.DataClass
final DateTime updatedAt;
final int? width;
final int? height;
- final int? durationInSeconds;
+ final int? durationMs;
final String id;
final String? checksum;
final bool isFavorite;
@@ -887,7 +884,7 @@ class LocalAssetEntityData extends i0.DataClass
required this.updatedAt,
this.width,
this.height,
- this.durationInSeconds,
+ this.durationMs,
required this.id,
this.checksum,
required this.isFavorite,
@@ -915,8 +912,8 @@ class LocalAssetEntityData extends i0.DataClass
if (!nullToAbsent || height != null) {
map['height'] = i0.Variable(height);
}
- if (!nullToAbsent || durationInSeconds != null) {
- map['duration_in_seconds'] = i0.Variable(durationInSeconds);
+ if (!nullToAbsent || durationMs != null) {
+ map['duration_ms'] = i0.Variable(durationMs);
}
map['id'] = i0.Variable(id);
if (!nullToAbsent || checksum != null) {
@@ -958,7 +955,7 @@ class LocalAssetEntityData extends i0.DataClass
updatedAt: serializer.fromJson(json['updatedAt']),
width: serializer.fromJson(json['width']),
height: serializer.fromJson(json['height']),
- durationInSeconds: serializer.fromJson(json['durationInSeconds']),
+ durationMs: serializer.fromJson(json['durationMs']),
id: serializer.fromJson(json['id']),
checksum: serializer.fromJson(json['checksum']),
isFavorite: serializer.fromJson(json['isFavorite']),
@@ -984,7 +981,7 @@ class LocalAssetEntityData extends i0.DataClass
'updatedAt': serializer.toJson(updatedAt),
'width': serializer.toJson(width),
'height': serializer.toJson(height),
- 'durationInSeconds': serializer.toJson(durationInSeconds),
+ 'durationMs': serializer.toJson(durationMs),
'id': serializer.toJson(id),
'checksum': serializer.toJson(checksum),
'isFavorite': serializer.toJson(isFavorite),
@@ -1006,7 +1003,7 @@ class LocalAssetEntityData extends i0.DataClass
DateTime? updatedAt,
i0.Value width = const i0.Value.absent(),
i0.Value height = const i0.Value.absent(),
- i0.Value durationInSeconds = const i0.Value.absent(),
+ i0.Value durationMs = const i0.Value.absent(),
String? id,
i0.Value checksum = const i0.Value.absent(),
bool? isFavorite,
@@ -1023,9 +1020,7 @@ class LocalAssetEntityData extends i0.DataClass
updatedAt: updatedAt ?? this.updatedAt,
width: width.present ? width.value : this.width,
height: height.present ? height.value : this.height,
- durationInSeconds: durationInSeconds.present
- ? durationInSeconds.value
- : this.durationInSeconds,
+ durationMs: durationMs.present ? durationMs.value : this.durationMs,
id: id ?? this.id,
checksum: checksum.present ? checksum.value : this.checksum,
isFavorite: isFavorite ?? this.isFavorite,
@@ -1046,9 +1041,9 @@ class LocalAssetEntityData extends i0.DataClass
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
width: data.width.present ? data.width.value : this.width,
height: data.height.present ? data.height.value : this.height,
- durationInSeconds: data.durationInSeconds.present
- ? data.durationInSeconds.value
- : this.durationInSeconds,
+ durationMs: data.durationMs.present
+ ? data.durationMs.value
+ : this.durationMs,
id: data.id.present ? data.id.value : this.id,
checksum: data.checksum.present ? data.checksum.value : this.checksum,
isFavorite: data.isFavorite.present
@@ -1078,7 +1073,7 @@ class LocalAssetEntityData extends i0.DataClass
..write('updatedAt: $updatedAt, ')
..write('width: $width, ')
..write('height: $height, ')
- ..write('durationInSeconds: $durationInSeconds, ')
+ ..write('durationMs: $durationMs, ')
..write('id: $id, ')
..write('checksum: $checksum, ')
..write('isFavorite: $isFavorite, ')
@@ -1100,7 +1095,7 @@ class LocalAssetEntityData extends i0.DataClass
updatedAt,
width,
height,
- durationInSeconds,
+ durationMs,
id,
checksum,
isFavorite,
@@ -1121,7 +1116,7 @@ class LocalAssetEntityData extends i0.DataClass
other.updatedAt == this.updatedAt &&
other.width == this.width &&
other.height == this.height &&
- other.durationInSeconds == this.durationInSeconds &&
+ other.durationMs == this.durationMs &&
other.id == this.id &&
other.checksum == this.checksum &&
other.isFavorite == this.isFavorite &&
@@ -1141,7 +1136,7 @@ class LocalAssetEntityCompanion
final i0.Value updatedAt;
final i0.Value width;
final i0.Value height;
- final i0.Value durationInSeconds;
+ final i0.Value durationMs;
final i0.Value id;
final i0.Value checksum;
final i0.Value isFavorite;
@@ -1158,7 +1153,7 @@ class LocalAssetEntityCompanion
this.updatedAt = const i0.Value.absent(),
this.width = const i0.Value.absent(),
this.height = const i0.Value.absent(),
- this.durationInSeconds = const i0.Value.absent(),
+ this.durationMs = const i0.Value.absent(),
this.id = const i0.Value.absent(),
this.checksum = const i0.Value.absent(),
this.isFavorite = const i0.Value.absent(),
@@ -1176,7 +1171,7 @@ class LocalAssetEntityCompanion
this.updatedAt = const i0.Value.absent(),
this.width = const i0.Value.absent(),
this.height = const i0.Value.absent(),
- this.durationInSeconds = const i0.Value.absent(),
+ this.durationMs = const i0.Value.absent(),
required String id,
this.checksum = const i0.Value.absent(),
this.isFavorite = const i0.Value.absent(),
@@ -1196,7 +1191,7 @@ class LocalAssetEntityCompanion
i0.Expression? updatedAt,
i0.Expression? width,
i0.Expression? height,
- i0.Expression? durationInSeconds,
+ i0.Expression? durationMs,
i0.Expression? id,
i0.Expression? checksum,
i0.Expression? isFavorite,
@@ -1214,7 +1209,7 @@ class LocalAssetEntityCompanion
if (updatedAt != null) 'updated_at': updatedAt,
if (width != null) 'width': width,
if (height != null) 'height': height,
- if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
+ if (durationMs != null) 'duration_ms': durationMs,
if (id != null) 'id': id,
if (checksum != null) 'checksum': checksum,
if (isFavorite != null) 'is_favorite': isFavorite,
@@ -1234,7 +1229,7 @@ class LocalAssetEntityCompanion
i0.Value? updatedAt,
i0.Value? width,
i0.Value? height,
- i0.Value? durationInSeconds,
+ i0.Value? durationMs,
i0.Value? id,
i0.Value? checksum,
i0.Value? isFavorite,
@@ -1252,7 +1247,7 @@ class LocalAssetEntityCompanion
updatedAt: updatedAt ?? this.updatedAt,
width: width ?? this.width,
height: height ?? this.height,
- durationInSeconds: durationInSeconds ?? this.durationInSeconds,
+ durationMs: durationMs ?? this.durationMs,
id: id ?? this.id,
checksum: checksum ?? this.checksum,
isFavorite: isFavorite ?? this.isFavorite,
@@ -1288,8 +1283,8 @@ class LocalAssetEntityCompanion
if (height.present) {
map['height'] = i0.Variable(height.value);
}
- if (durationInSeconds.present) {
- map['duration_in_seconds'] = i0.Variable(durationInSeconds.value);
+ if (durationMs.present) {
+ map['duration_ms'] = i0.Variable(durationMs.value);
}
if (id.present) {
map['id'] = i0.Variable(id.value);
@@ -1334,7 +1329,7 @@ class LocalAssetEntityCompanion
..write('updatedAt: $updatedAt, ')
..write('width: $width, ')
..write('height: $height, ')
- ..write('durationInSeconds: $durationInSeconds, ')
+ ..write('durationMs: $durationMs, ')
..write('id: $id, ')
..write('checksum: $checksum, ')
..write('isFavorite: $isFavorite, ')
diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift b/mobile/lib/infrastructure/entities/merged_asset.drift
index 73276d1756..daad02e2b3 100644
--- a/mobile/lib/infrastructure/entities/merged_asset.drift
+++ b/mobile/lib/infrastructure/entities/merged_asset.drift
@@ -14,7 +14,7 @@ SELECT
rae.updated_at,
rae.width,
rae.height,
- rae.duration_in_seconds,
+ rae.duration_ms,
rae.is_favorite,
rae.thumb_hash,
rae.checksum,
@@ -52,7 +52,7 @@ SELECT
lae.updated_at,
lae.width,
lae.height,
- lae.duration_in_seconds,
+ lae.duration_ms,
lae.is_favorite,
NULL as thumb_hash,
lae.checksum,
diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift.dart b/mobile/lib/infrastructure/entities/merged_asset.drift.dart
index c6004eb10d..1e501d4028 100644
--- a/mobile/lib/infrastructure/entities/merged_asset.drift.dart
+++ b/mobile/lib/infrastructure/entities/merged_asset.drift.dart
@@ -29,7 +29,7 @@ class MergedAssetDrift extends i1.ModularAccessor {
);
$arrayStartIndex += generatedlimit.amountOfVariables;
return customSelect(
- 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS 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, NULL AS i_cloud_id, NULL AS latitude, NULL AS longitude, NULL AS adjustmentTime, rae.is_edited, 0 AS playback_style FROM remote_asset_entity AS rae 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 ($expandeduserIds) 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 AS 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, lae.i_cloud_id, lae.latitude, lae.longitude, lae.adjustment_time, 0 AS is_edited, lae.playback_style FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}',
+ 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_ms, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, NULL AS i_cloud_id, NULL AS latitude, NULL AS longitude, NULL AS adjustmentTime, rae.is_edited, 0 AS playback_style FROM remote_asset_entity AS rae 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 ($expandeduserIds) 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 AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_ms, 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, lae.i_cloud_id, lae.latitude, lae.longitude, lae.adjustment_time, 0 AS is_edited, lae.playback_style FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}',
variables: [
for (var $ in userIds) i0.Variable($),
...generatedlimit.introducedVariables,
@@ -54,7 +54,7 @@ class MergedAssetDrift extends i1.ModularAccessor {
updatedAt: row.read('updated_at'),
width: row.readNullable('width'),
height: row.readNullable('height'),
- durationInSeconds: row.readNullable('duration_in_seconds'),
+ durationMs: row.readNullable('duration_ms'),
isFavorite: row.read('is_favorite'),
thumbHash: row.readNullable('thumb_hash'),
checksum: row.readNullable('checksum'),
@@ -127,7 +127,7 @@ class MergedAssetResult {
final DateTime updatedAt;
final int? width;
final int? height;
- final int? durationInSeconds;
+ final int? durationMs;
final bool isFavorite;
final String? thumbHash;
final String? checksum;
@@ -150,7 +150,7 @@ class MergedAssetResult {
required this.updatedAt,
this.width,
this.height,
- this.durationInSeconds,
+ this.durationMs,
required this.isFavorite,
this.thumbHash,
this.checksum,
diff --git a/mobile/lib/infrastructure/entities/remote_album.entity.dart b/mobile/lib/infrastructure/entities/remote_album.entity.dart
index 30e13853d8..d12d511148 100644
--- a/mobile/lib/infrastructure/entities/remote_album.entity.dart
+++ b/mobile/lib/infrastructure/entities/remote_album.entity.dart
@@ -1,10 +1,8 @@
import 'package:drift/drift.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
-import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
-@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_remote_album_owner_id ON remote_album_entity (owner_id)')
class RemoteAlbumEntity extends Table with DriftDefaultsMixin {
const RemoteAlbumEntity();
@@ -18,8 +16,6 @@ class RemoteAlbumEntity extends Table with DriftDefaultsMixin {
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
- TextColumn get ownerId => text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
-
TextColumn get thumbnailAssetId =>
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.setNull).nullable()();
diff --git a/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart b/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart
index 7dc864b978..8fdabe0b15 100644
--- a/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart
+++ b/mobile/lib/infrastructure/entities/remote_album.entity.drift.dart
@@ -7,11 +7,9 @@ import 'package:immich_mobile/domain/models/album/album.model.dart' as i2;
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart'
as i3;
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i4;
-import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
+import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
as i5;
import 'package:drift/internal/modular.dart' as i6;
-import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
- as i7;
typedef $$RemoteAlbumEntityTableCreateCompanionBuilder =
i1.RemoteAlbumEntityCompanion Function({
@@ -20,7 +18,6 @@ typedef $$RemoteAlbumEntityTableCreateCompanionBuilder =
i0.Value description,
i0.Value createdAt,
i0.Value updatedAt,
- required String ownerId,
i0.Value thumbnailAssetId,
i0.Value isActivityEnabled,
required i2.AlbumAssetOrder order,
@@ -32,7 +29,6 @@ typedef $$RemoteAlbumEntityTableUpdateCompanionBuilder =
i0.Value description,
i0.Value createdAt,
i0.Value updatedAt,
- i0.Value ownerId,
i0.Value thumbnailAssetId,
i0.Value isActivityEnabled,
i0.Value order,
@@ -51,42 +47,10 @@ final class $$RemoteAlbumEntityTableReferences
super.$_typedResult,
);
- static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
- i6.ReadDatabaseContainer(db)
- .resultSet('user_entity')
- .createAlias(
- i0.$_aliasNameGenerator(
- i6.ReadDatabaseContainer(db)
- .resultSet('remote_album_entity')
- .ownerId,
- i6.ReadDatabaseContainer(
- db,
- ).resultSet('user_entity').id,
- ),
- );
-
- i5.$$UserEntityTableProcessedTableManager get ownerId {
- final $_column = $_itemColumn('owner_id')!;
-
- final manager = i5
- .$$UserEntityTableTableManager(
- $_db,
- i6.ReadDatabaseContainer(
- $_db,
- ).resultSet('user_entity'),
- )
- .filter((f) => f.id.sqlEquals($_column));
- final item = $_typedResult.readTableOrNull(_ownerIdTable($_db));
- if (item == null) return manager;
- return i0.ProcessedTableManager(
- manager.$state.copyWith(prefetchedData: [item]),
- );
- }
-
- static i7.$RemoteAssetEntityTable _thumbnailAssetIdTable(
+ static i5.$RemoteAssetEntityTable _thumbnailAssetIdTable(
i0.GeneratedDatabase db,
) => i6.ReadDatabaseContainer(db)
- .resultSet('remote_asset_entity')
+ .resultSet('remote_asset_entity')
.createAlias(
i0.$_aliasNameGenerator(
i6.ReadDatabaseContainer(db)
@@ -94,19 +58,19 @@ final class $$RemoteAlbumEntityTableReferences
.thumbnailAssetId,
i6.ReadDatabaseContainer(
db,
- ).resultSet('remote_asset_entity').id,
+ ).resultSet('remote_asset_entity').id,
),
);
- i7.$$RemoteAssetEntityTableProcessedTableManager? get thumbnailAssetId {
+ i5.$$RemoteAssetEntityTableProcessedTableManager? get thumbnailAssetId {
final $_column = $_itemColumn('thumbnail_asset_id');
if ($_column == null) return null;
- final manager = i7
+ final manager = i5
.$$RemoteAssetEntityTableTableManager(
$_db,
i6.ReadDatabaseContainer(
$_db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
)
.filter((f) => f.id.sqlEquals($_column));
final item = $_typedResult.readTableOrNull(_thumbnailAssetIdTable($_db));
@@ -162,51 +126,24 @@ class $$RemoteAlbumEntityTableFilterComposer
builder: (column) => i0.ColumnWithTypeConverterFilters(column),
);
- i5.$$UserEntityTableFilterComposer get ownerId {
- final i5.$$UserEntityTableFilterComposer composer = $composerBuilder(
- composer: this,
- getCurrentColumn: (t) => t.ownerId,
- referencedTable: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- getReferencedColumn: (t) => t.id,
- builder:
- (
- joinBuilder, {
- $addJoinBuilderToRootComposer,
- $removeJoinBuilderFromRootComposer,
- }) => i5.$$UserEntityTableFilterComposer(
- $db: $db,
- $table: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
- joinBuilder: joinBuilder,
- $removeJoinBuilderFromRootComposer:
- $removeJoinBuilderFromRootComposer,
- ),
- );
- return composer;
- }
-
- i7.$$RemoteAssetEntityTableFilterComposer get thumbnailAssetId {
- final i7.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
+ i5.$$RemoteAssetEntityTableFilterComposer get thumbnailAssetId {
+ final i5.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
composer: this,
getCurrentColumn: (t) => t.thumbnailAssetId,
referencedTable: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder:
(
joinBuilder, {
$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer,
- }) => i7.$$RemoteAssetEntityTableFilterComposer(
+ }) => i5.$$RemoteAssetEntityTableFilterComposer(
$db: $db,
$table: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
@@ -261,52 +198,25 @@ class $$RemoteAlbumEntityTableOrderingComposer
builder: (column) => i0.ColumnOrderings(column),
);
- i5.$$UserEntityTableOrderingComposer get ownerId {
- final i5.$$UserEntityTableOrderingComposer composer = $composerBuilder(
- composer: this,
- getCurrentColumn: (t) => t.ownerId,
- referencedTable: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- getReferencedColumn: (t) => t.id,
- builder:
- (
- joinBuilder, {
- $addJoinBuilderToRootComposer,
- $removeJoinBuilderFromRootComposer,
- }) => i5.$$UserEntityTableOrderingComposer(
- $db: $db,
- $table: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
- joinBuilder: joinBuilder,
- $removeJoinBuilderFromRootComposer:
- $removeJoinBuilderFromRootComposer,
- ),
- );
- return composer;
- }
-
- i7.$$RemoteAssetEntityTableOrderingComposer get thumbnailAssetId {
- final i7.$$RemoteAssetEntityTableOrderingComposer composer =
+ i5.$$RemoteAssetEntityTableOrderingComposer get thumbnailAssetId {
+ final i5.$$RemoteAssetEntityTableOrderingComposer composer =
$composerBuilder(
composer: this,
getCurrentColumn: (t) => t.thumbnailAssetId,
referencedTable: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder:
(
joinBuilder, {
$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer,
- }) => i7.$$RemoteAssetEntityTableOrderingComposer(
+ }) => i5.$$RemoteAssetEntityTableOrderingComposer(
$db: $db,
$table: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
@@ -351,52 +261,25 @@ class $$RemoteAlbumEntityTableAnnotationComposer
i0.GeneratedColumnWithTypeConverter get order =>
$composableBuilder(column: $table.order, builder: (column) => column);
- i5.$$UserEntityTableAnnotationComposer get ownerId {
- final i5.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
- composer: this,
- getCurrentColumn: (t) => t.ownerId,
- referencedTable: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- getReferencedColumn: (t) => t.id,
- builder:
- (
- joinBuilder, {
- $addJoinBuilderToRootComposer,
- $removeJoinBuilderFromRootComposer,
- }) => i5.$$UserEntityTableAnnotationComposer(
- $db: $db,
- $table: i6.ReadDatabaseContainer(
- $db,
- ).resultSet('user_entity'),
- $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
- joinBuilder: joinBuilder,
- $removeJoinBuilderFromRootComposer:
- $removeJoinBuilderFromRootComposer,
- ),
- );
- return composer;
- }
-
- i7.$$RemoteAssetEntityTableAnnotationComposer get thumbnailAssetId {
- final i7.$$RemoteAssetEntityTableAnnotationComposer composer =
+ i5.$$RemoteAssetEntityTableAnnotationComposer get thumbnailAssetId {
+ final i5.$$RemoteAssetEntityTableAnnotationComposer composer =
$composerBuilder(
composer: this,
getCurrentColumn: (t) => t.thumbnailAssetId,
referencedTable: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
getReferencedColumn: (t) => t.id,
builder:
(
joinBuilder, {
$addJoinBuilderToRootComposer,
$removeJoinBuilderFromRootComposer,
- }) => i7.$$RemoteAssetEntityTableAnnotationComposer(
+ }) => i5.$$RemoteAssetEntityTableAnnotationComposer(
$db: $db,
$table: i6.ReadDatabaseContainer(
$db,
- ).resultSet('remote_asset_entity'),
+ ).resultSet('remote_asset_entity'),
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
joinBuilder: joinBuilder,
$removeJoinBuilderFromRootComposer:
@@ -420,7 +303,7 @@ class $$RemoteAlbumEntityTableTableManager
$$RemoteAlbumEntityTableUpdateCompanionBuilder,
(i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences),
i1.RemoteAlbumEntityData,
- i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})
+ i0.PrefetchHooks Function({bool thumbnailAssetId})
> {
$$RemoteAlbumEntityTableTableManager(
i0.GeneratedDatabase db,
@@ -445,7 +328,6 @@ class $$RemoteAlbumEntityTableTableManager
i0.Value description = const i0.Value.absent(),
i0.Value createdAt = const i0.Value.absent(),
i0.Value updatedAt = const i0.Value.absent(),
- i0.Value ownerId = const i0.Value.absent(),
i0.Value thumbnailAssetId = const i0.Value.absent(),
i0.Value isActivityEnabled = const i0.Value.absent(),
i0.Value order = const i0.Value.absent(),
@@ -455,7 +337,6 @@ class $$RemoteAlbumEntityTableTableManager
description: description,
createdAt: createdAt,
updatedAt: updatedAt,
- ownerId: ownerId,
thumbnailAssetId: thumbnailAssetId,
isActivityEnabled: isActivityEnabled,
order: order,
@@ -467,7 +348,6 @@ class $$RemoteAlbumEntityTableTableManager
i0.Value description = const i0.Value.absent(),
i0.Value createdAt = const i0.Value.absent(),
i0.Value updatedAt = const i0.Value.absent(),
- required String ownerId,
i0.Value thumbnailAssetId = const i0.Value.absent(),
i0.Value isActivityEnabled = const i0.Value.absent(),
required i2.AlbumAssetOrder order,
@@ -477,7 +357,6 @@ class $$RemoteAlbumEntityTableTableManager
description: description,
createdAt: createdAt,
updatedAt: updatedAt,
- ownerId: ownerId,
thumbnailAssetId: thumbnailAssetId,
isActivityEnabled: isActivityEnabled,
order: order,
@@ -490,7 +369,7 @@ class $$RemoteAlbumEntityTableTableManager
),
)
.toList(),
- prefetchHooksCallback: ({ownerId = false, thumbnailAssetId = false}) {
+ prefetchHooksCallback: ({thumbnailAssetId = false}) {
return i0.PrefetchHooks(
db: db,
explicitlyWatchedTables: [],
@@ -510,21 +389,6 @@ class $$RemoteAlbumEntityTableTableManager
dynamic
>
>(state) {
- if (ownerId) {
- state =
- state.withJoin(
- currentTable: table,
- currentColumn: table.ownerId,
- referencedTable: i1
- .$$RemoteAlbumEntityTableReferences
- ._ownerIdTable(db),
- referencedColumn: i1
- .$$RemoteAlbumEntityTableReferences
- ._ownerIdTable(db)
- .id,
- )
- as T;
- }
if (thumbnailAssetId) {
state =
state.withJoin(
@@ -564,12 +428,8 @@ typedef $$RemoteAlbumEntityTableProcessedTableManager =
$$RemoteAlbumEntityTableUpdateCompanionBuilder,
(i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences),
i1.RemoteAlbumEntityData,
- i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})
+ i0.PrefetchHooks Function({bool thumbnailAssetId})
>;
-i0.Index get idxRemoteAlbumOwnerId => i0.Index(
- 'idx_remote_album_owner_id',
- 'CREATE INDEX IF NOT EXISTS idx_remote_album_owner_id ON remote_album_entity (owner_id)',
-);
class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
with i0.TableInfo<$RemoteAlbumEntityTable, i1.RemoteAlbumEntityData> {
@@ -636,20 +496,6 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
requiredDuringInsert: false,
defaultValue: i4.currentDateAndTime,
);
- static const i0.VerificationMeta _ownerIdMeta = const i0.VerificationMeta(
- 'ownerId',
- );
- @override
- late final i0.GeneratedColumn ownerId = i0.GeneratedColumn(
- 'owner_id',
- aliasedName,
- false,
- type: i0.DriftSqlType.string,
- requiredDuringInsert: true,
- defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
- 'REFERENCES user_entity (id) ON DELETE CASCADE',
- ),
- );
static const i0.VerificationMeta _thumbnailAssetIdMeta =
const i0.VerificationMeta('thumbnailAssetId');
@override
@@ -698,7 +544,6 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
description,
createdAt,
updatedAt,
- ownerId,
thumbnailAssetId,
isActivityEnabled,
order,
@@ -749,14 +594,6 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta),
);
}
- if (data.containsKey('owner_id')) {
- context.handle(
- _ownerIdMeta,
- ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta),
- );
- } else if (isInserting) {
- context.missing(_ownerIdMeta);
- }
if (data.containsKey('thumbnail_asset_id')) {
context.handle(
_thumbnailAssetIdMeta,
@@ -807,10 +644,6 @@ class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
i0.DriftSqlType.dateTime,
data['${effectivePrefix}updated_at'],
)!,
- ownerId: attachedDatabase.typeMapping.read(
- i0.DriftSqlType.string,
- data['${effectivePrefix}owner_id'],
- )!,
thumbnailAssetId: attachedDatabase.typeMapping.read(
i0.DriftSqlType.string,
data['${effectivePrefix}thumbnail_asset_id'],
@@ -850,7 +683,6 @@ class RemoteAlbumEntityData extends i0.DataClass
final String description;
final DateTime createdAt;
final DateTime updatedAt;
- final String ownerId;
final String? thumbnailAssetId;
final bool isActivityEnabled;
final i2.AlbumAssetOrder order;
@@ -860,7 +692,6 @@ class RemoteAlbumEntityData extends i0.DataClass
required this.description,
required this.createdAt,
required this.updatedAt,
- required this.ownerId,
this.thumbnailAssetId,
required this.isActivityEnabled,
required this.order,
@@ -873,7 +704,6 @@ class RemoteAlbumEntityData extends i0.DataClass
map['description'] = i0.Variable(description);
map['created_at'] = i0.Variable(createdAt);
map['updated_at'] = i0.Variable(updatedAt);
- map['owner_id'] = i0.Variable(ownerId);
if (!nullToAbsent || thumbnailAssetId != null) {
map['thumbnail_asset_id'] = i0.Variable(thumbnailAssetId);
}
@@ -897,7 +727,6 @@ class RemoteAlbumEntityData extends i0.DataClass
description: serializer.fromJson(json['description']),
createdAt: serializer.fromJson(json['createdAt']),
updatedAt: serializer.fromJson(json['updatedAt']),
- ownerId: serializer.fromJson(json['ownerId']),
thumbnailAssetId: serializer.fromJson(json['thumbnailAssetId']),
isActivityEnabled: serializer.fromJson(json['isActivityEnabled']),
order: i1.$RemoteAlbumEntityTable.$converterorder.fromJson(
@@ -914,7 +743,6 @@ class RemoteAlbumEntityData extends i0.DataClass
'description': serializer.toJson(description),
'createdAt': serializer.toJson(createdAt),
'updatedAt': serializer.toJson