mirror of
https://github.com/immich-app/immich.git
synced 2025-07-07 10:14:08 -04:00
wip
This commit is contained in:
commit
429d339c6d
@ -1,4 +1,4 @@
|
||||
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:fb211a0ea31a6177507498c084682aae8c9c31ca27668ea122246aa16a4723a0
|
||||
ARG BASEIMAGE=mcr.microsoft.com/devcontainers/typescript-node:22@sha256:7c2e711a4f7b02f32d2da16192d5e05aa7c95279be4ce889cff5df316f251c1d
|
||||
FROM ${BASEIMAGE}
|
||||
|
||||
# Flutter SDK
|
||||
|
20
.github/workflows/docker.yml
vendored
20
.github/workflows/docker.yml
vendored
@ -177,13 +177,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
- name: Any jobs failed?
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
run: exit 1
|
||||
- name: All jobs passed or skipped
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
# zizmor: ignore[template-injection]
|
||||
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
|
||||
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||
with:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
||||
success-check-ml:
|
||||
name: Docker Build & Push ML Success
|
||||
@ -192,10 +188,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
- name: Any jobs failed?
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
run: exit 1
|
||||
- name: All jobs passed or skipped
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
# zizmor: ignore[template-injection]
|
||||
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
|
||||
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||
with:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
12
.github/workflows/static_analysis.yml
vendored
12
.github/workflows/static_analysis.yml
vendored
@ -58,6 +58,14 @@ jobs:
|
||||
run: dart pub get
|
||||
working-directory: ./mobile
|
||||
|
||||
- name: Install DCM
|
||||
run: |
|
||||
sudo apt-get update
|
||||
wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg
|
||||
echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install dcm
|
||||
|
||||
- name: Generate translation file
|
||||
run: make translation
|
||||
working-directory: ./mobile
|
||||
@ -100,6 +108,10 @@ jobs:
|
||||
run: dart run custom_lint
|
||||
working-directory: ./mobile
|
||||
|
||||
- name: Run DCM
|
||||
run: dcm analyze lib
|
||||
working-directory: ./mobile
|
||||
|
||||
zizmor:
|
||||
name: zizmor
|
||||
runs-on: ubuntu-latest
|
||||
|
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@ -479,13 +479,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
steps:
|
||||
- name: Any jobs failed?
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
run: exit 1
|
||||
- name: All jobs passed or skipped
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
# zizmor: ignore[template-injection]
|
||||
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
|
||||
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||
with:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
||||
mobile-unit-tests:
|
||||
name: Unit Test Mobile
|
||||
|
10
.github/workflows/weblate-lock.yml
vendored
10
.github/workflows/weblate-lock.yml
vendored
@ -52,10 +52,6 @@ jobs:
|
||||
permissions: {}
|
||||
if: always()
|
||||
steps:
|
||||
- name: Any jobs failed?
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
run: exit 1
|
||||
- name: All jobs passed or skipped
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
# zizmor: ignore[template-injection]
|
||||
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
|
||||
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||
with:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
280
cli/package-lock.json
generated
280
cli/package-lock.json
generated
@ -27,7 +27,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/node": "^22.15.29",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
@ -35,7 +35,7 @@
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^57.0.0",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
@ -61,7 +61,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/node": "^22.15.29",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -79,21 +79,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.26.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
|
||||
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.9",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
|
||||
@ -1353,22 +1338,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.15.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
|
||||
"integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
|
||||
"version": "22.15.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz",
|
||||
"integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/normalize-package-data": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
|
||||
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz",
|
||||
@ -1878,9 +1856,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/builtin-modules": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-4.0.0.tgz",
|
||||
"integrity": "sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz",
|
||||
"integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -2362,50 +2340,65 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn": {
|
||||
"version": "57.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-57.0.0.tgz",
|
||||
"integrity": "sha512-zUYYa6zfNdTeG9BISWDlcLmz16c+2Ck2o5ZDHh0UzXJz3DEP7xjmlVDTzbyV0W+XksgZ0q37WEWzN2D2Ze+g9Q==",
|
||||
"version": "59.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz",
|
||||
"integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.25.9",
|
||||
"@eslint-community/eslint-utils": "^4.4.1",
|
||||
"ci-info": "^4.1.0",
|
||||
"@eslint-community/eslint-utils": "^4.5.1",
|
||||
"@eslint/plugin-kit": "^0.2.7",
|
||||
"ci-info": "^4.2.0",
|
||||
"clean-regexp": "^1.0.0",
|
||||
"core-js-compat": "^3.40.0",
|
||||
"core-js-compat": "^3.41.0",
|
||||
"esquery": "^1.6.0",
|
||||
"globals": "^15.15.0",
|
||||
"find-up-simple": "^1.0.1",
|
||||
"globals": "^16.0.0",
|
||||
"indent-string": "^5.0.0",
|
||||
"is-builtin-module": "^4.0.0",
|
||||
"is-builtin-module": "^5.0.0",
|
||||
"jsesc": "^3.1.0",
|
||||
"pluralize": "^8.0.0",
|
||||
"read-package-up": "^11.0.0",
|
||||
"regexp-tree": "^0.1.27",
|
||||
"regjsparser": "^0.12.0",
|
||||
"semver": "^7.7.1",
|
||||
"strip-indent": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
"node": "^18.20.0 || ^20.10.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=9.20.0"
|
||||
"eslint": ">=9.22.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/globals": {
|
||||
"version": "15.15.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
|
||||
"integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
|
||||
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
|
||||
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.13.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
@ -2792,19 +2785,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/hosted-git-info": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
|
||||
"integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-escaper": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||
@ -2862,27 +2842,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/index-to-position": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz",
|
||||
"integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-builtin-module": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-4.0.0.tgz",
|
||||
"integrity": "sha512-rWP3AMAalQSesXO8gleROyL2iKU73SX5Er66losQn9rWOWL4Gef0a/xOEOVqjWGMuR2vHG3FJ8UUmT700O8oFg==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz",
|
||||
"integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"builtin-modules": "^4.0.0"
|
||||
"builtin-modules": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.20"
|
||||
@ -3008,13 +2975,6 @@
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
@ -3272,21 +3232,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-package-data": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
|
||||
"integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"hosted-git-info": "^7.0.0",
|
||||
"semver": "^7.3.5",
|
||||
"validate-npm-package-license": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
@ -3357,24 +3302,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
|
||||
"integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"index-to-position": "^1.1.0",
|
||||
"type-fest": "^4.39.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@ -3573,44 +3500,6 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/read-package-up": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
|
||||
"integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"find-up-simple": "^1.0.0",
|
||||
"read-pkg": "^9.0.0",
|
||||
"type-fest": "^4.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
|
||||
"integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/normalize-package-data": "^2.4.3",
|
||||
"normalize-package-data": "^6.0.0",
|
||||
"parse-json": "^8.0.0",
|
||||
"type-fest": "^4.6.0",
|
||||
"unicorn-magic": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
@ -3809,42 +3698,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/spdx-correct": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
|
||||
"integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"spdx-expression-parse": "^3.0.0",
|
||||
"spdx-license-ids": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/spdx-exceptions": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
|
||||
"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
|
||||
"dev": true,
|
||||
"license": "CC-BY-3.0"
|
||||
},
|
||||
"node_modules/spdx-expression-parse": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
|
||||
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"spdx-exceptions": "^2.1.0",
|
||||
"spdx-license-ids": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/spdx-license-ids": {
|
||||
"version": "3.0.21",
|
||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
|
||||
"integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/stackback": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
||||
@ -4172,19 +4025,6 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.40.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz",
|
||||
"integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
@ -4229,19 +4069,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unicorn-magic": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
|
||||
"integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
||||
@ -4283,17 +4110,6 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"spdx-correct": "^3.0.0",
|
||||
"spdx-expression-parse": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
|
@ -21,7 +21,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/node": "^22.15.29",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
@ -29,7 +29,7 @@
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^57.0.0",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.2.5",
|
||||
|
@ -82,7 +82,7 @@ services:
|
||||
container_name: immich_prometheus
|
||||
ports:
|
||||
- 9090:9090
|
||||
image: prom/prometheus@sha256:78ed1f9050eb9eaf766af6e580230b1c4965728650e332cd1ee918c0c4699775
|
||||
image: prom/prometheus@sha256:9abc6cf6aea7710d163dbb28d8eeb7dc5baef01e38fa4cd146a406dd9f07f70d
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus-data:/prometheus
|
||||
@ -94,7 +94,7 @@ services:
|
||||
command: [ './run.sh', '-disable-reporting' ]
|
||||
ports:
|
||||
- 3000:3000
|
||||
image: grafana/grafana:11.6.1-ubuntu@sha256:6fc273288470ef499dd3c6b36aeade093170d4f608f864c5dd3a7fabeae77b50
|
||||
image: grafana/grafana:12.0.1-ubuntu@sha256:65575bb9c761335e2ff30e364f21d38632e3b2e75f5f81d83cc92f44b9bbc055
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
|
||||
|
790
e2e/package-lock.json
generated
790
e2e/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,8 +25,8 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/node": "^22.15.29",
|
||||
"@types/oidc-provider": "^9.0.0",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
@ -34,12 +34,12 @@
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^57.0.0",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"exiftool-vendored": "^28.3.1",
|
||||
"globals": "^16.0.0",
|
||||
"jose": "^5.6.3",
|
||||
"luxon": "^3.4.4",
|
||||
"oidc-provider": "^8.5.1",
|
||||
"oidc-provider": "^9.0.0",
|
||||
"pg": "^8.11.3",
|
||||
"pngjs": "^7.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
|
@ -22,6 +22,7 @@
|
||||
"add_partner": "Add partner",
|
||||
"add_path": "Add path",
|
||||
"add_photos": "Add photos",
|
||||
"add_tag": "Add tag",
|
||||
"add_to": "Add to…",
|
||||
"add_to_album": "Add to album",
|
||||
"add_to_album_bottom_sheet_added": "Added to {album}",
|
||||
@ -169,7 +170,7 @@
|
||||
"note_apply_storage_label_previous_assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
|
||||
"note_cannot_be_changed_later": "NOTE: This cannot be changed later!",
|
||||
"notification_email_from_address": "From address",
|
||||
"notification_email_from_address_description": "Sender email address, for example: \"Immich Photo Server <noreply@example.com>\"",
|
||||
"notification_email_from_address_description": "Sender email address, for example: \"Immich Photo Server <noreply@example.com>\". Make sure to use an address you're allowed to send emails from.",
|
||||
"notification_email_host_description": "Host of the email server (e.g. smtp.immich.app)",
|
||||
"notification_email_ignore_certificate_errors": "Ignore certificate errors",
|
||||
"notification_email_ignore_certificate_errors_description": "Ignore TLS certificate validation errors (not recommended)",
|
||||
@ -648,6 +649,7 @@
|
||||
"confirm_password": "Confirm password",
|
||||
"confirm_tag_face": "Do you want to tag this face as {name}?",
|
||||
"confirm_tag_face_unnamed": "Do you want to tag this face?",
|
||||
"connected_device": "Connected device",
|
||||
"connected_to": "Connected to",
|
||||
"contain": "Contain",
|
||||
"context": "Context",
|
||||
@ -748,6 +750,7 @@
|
||||
"disallow_edits": "Disallow edits",
|
||||
"discord": "Discord",
|
||||
"discover": "Discover",
|
||||
"discovered_devices": "Discovered devices",
|
||||
"dismiss_all_errors": "Dismiss all errors",
|
||||
"dismiss_error": "Dismiss error",
|
||||
"display_options": "Display options",
|
||||
@ -1132,6 +1135,7 @@
|
||||
"list": "List",
|
||||
"loading": "Loading",
|
||||
"loading_search_results_failed": "Loading search results failed",
|
||||
"local_asset_cast_failed": "Unable to cast an asset that is not uploaded to the server",
|
||||
"local_network": "Local network",
|
||||
"local_network_sheet_info": "The app will connect to the server through this URL when using the specified Wi-Fi network",
|
||||
"location_permission": "Location permission",
|
||||
@ -1272,6 +1276,7 @@
|
||||
"no_archived_assets_message": "Archive photos and videos to hide them from your Photos view",
|
||||
"no_assets_message": "CLICK TO UPLOAD YOUR FIRST PHOTO",
|
||||
"no_assets_to_show": "No assets to show",
|
||||
"no_cast_devices_found": "No cast devices found",
|
||||
"no_duplicates_found": "No duplicates were found.",
|
||||
"no_exif_info_available": "No exif info available",
|
||||
"no_explore_results_message": "Upload more photos to explore your collection.",
|
||||
@ -1630,6 +1635,7 @@
|
||||
"set_date_of_birth": "Set date of birth",
|
||||
"set_profile_picture": "Set profile picture",
|
||||
"set_slideshow_to_fullscreen": "Set Slideshow to fullscreen",
|
||||
"set_stack_primary_asset": "Set as primary asset",
|
||||
"setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).",
|
||||
"setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).",
|
||||
"setting_image_viewer_original_title": "Load original image",
|
||||
@ -1767,6 +1773,7 @@
|
||||
"start_date": "Start date",
|
||||
"state": "State",
|
||||
"status": "Status",
|
||||
"stop_casting": "Stop casting",
|
||||
"stop_motion_photo": "Stop Motion Photo",
|
||||
"stop_photo_sharing": "Stop sharing your photos?",
|
||||
"stop_photo_sharing_description": "{partner} will no longer be able to access your photos.",
|
||||
|
@ -1,6 +1,6 @@
|
||||
ARG DEVICE=cpu
|
||||
|
||||
FROM python:3.11-bookworm@sha256:ab60e444e04215a62671149f24c59cc2893b49cb5dad26f9d139077a86be760e AS builder-cpu
|
||||
FROM python:3.11-bookworm@sha256:d2621a9f74d31a8a60af19f97b09cc3ac54382c8680b6544018713a12ef6c048 AS builder-cpu
|
||||
|
||||
FROM builder-cpu AS builder-openvino
|
||||
|
||||
@ -59,7 +59,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:4a6c9444b126bd325fba904bff796bf91fb777bf6148d60109c4cb1de2ffc497 /uv /uvx /bin/
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:4faec156e35a5f345d57804d8858c6ba1cf6352ce5f4bffc11b7fdebdef46a38 /uv /uvx /bin/
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||
@ -68,11 +68,11 @@ RUN if [ "$DEVICE" = "rocm" ]; then \
|
||||
uv pip install /opt/onnxruntime_rocm-*.whl; \
|
||||
fi
|
||||
|
||||
FROM python:3.11-slim-bookworm@sha256:97ef3198ec8c78690587167bb6a4905d00ffe053900687bdae93ad667e507cbb AS prod-cpu
|
||||
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-cpu
|
||||
|
||||
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
|
||||
|
||||
FROM python:3.11-slim-bookworm@sha256:97ef3198ec8c78690587167bb6a4905d00ffe053900687bdae93ad667e507cbb AS prod-openvino
|
||||
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-openvino
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
||||
|
170
machine-learning/uv.lock
generated
170
machine-learning/uv.lock
generated
@ -346,11 +346,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "configargparse"
|
||||
version = "1.7"
|
||||
version = "1.7.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/70/8a/73f1008adfad01cb923255b924b1528727b8270e67cb4ef41eabdc7d783e/ConfigArgParse-1.7.tar.gz", hash = "sha256:e7067471884de5478c58a511e529f0f9bd1c66bfef1dea90935438d6c23306d1", size = 43817, upload-time = "2023-07-23T16:20:04.95Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/85/4d/6c9ef746dfcc2a32e26f3860bb4a011c008c392b83eabdfb598d1a8bbe5d/configargparse-1.7.1.tar.gz", hash = "sha256:79c2ddae836a1e5914b71d58e4b9adbd9f7779d4e6351a637b7d2d9b6c46d3d9", size = 43958, upload-time = "2025-05-23T14:26:17.369Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/b3/b4ac838711fd74a2b4e6f746703cf9dd2cf5462d17dac07e349234e21b97/ConfigArgParse-1.7-py3-none-any.whl", hash = "sha256:d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b", size = 25489, upload-time = "2023-07-23T16:20:03.27Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/28/d28211d29bcc3620b1fece85a65ce5bb22f18670a03cd28ea4b75ede270c/configargparse-1.7.1-py3-none-any.whl", hash = "sha256:8b586a31f9d873abd1ca527ffbe58863c99f36d896e2829779803125e83be4b6", size = 25607, upload-time = "2025-05-23T14:26:15.923Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -900,7 +900,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "huggingface-hub"
|
||||
version = "0.32.2"
|
||||
version = "0.32.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "filelock" },
|
||||
@ -912,9 +912,9 @@ dependencies = [
|
||||
{ name = "tqdm" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/76/44f7025d1b3f29336aeb7324a57dd7c19f7c69f6612b7637b39ac7c17302/huggingface_hub-0.32.2.tar.gz", hash = "sha256:64a288b1eadad6b60bbfd50f0e52fd6cfa2ef77ab13c3e8a834a038ae929de54", size = 422847, upload-time = "2025-05-27T09:23:00.306Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/c8/4f7d270285c46324fd66f62159eb16739aa5696f422dba57678a8c6b78e9/huggingface_hub-0.32.4.tar.gz", hash = "sha256:f61d45cd338736f59fb0e97550b74c24ee771bcc92c05ae0766b9116abe720be", size = 424494, upload-time = "2025-06-03T09:59:46.105Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/30/532fe57467a6cc7ff2e39f088db1cb6d6bf522f724a4a5c7beda1282d5a6/huggingface_hub-0.32.2-py3-none-any.whl", hash = "sha256:f8fcf14603237eadf96dbe577d30b330f8c27b4a0a31e8f6c94fdc25e021fdb8", size = 509968, upload-time = "2025-05-27T09:22:57.967Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/8b/222140f3cfb6f17b0dd8c4b9a0b36bd4ebefe9fb0098ba35d6960abcda0f/huggingface_hub-0.32.4-py3-none-any.whl", hash = "sha256:37abf8826b38d971f60d3625229221c36e53fe58060286db9baf619cfbf39767", size = 512101, upload-time = "2025-06-03T09:59:44.099Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1225,7 +1225,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "locust"
|
||||
version = "2.37.5"
|
||||
version = "2.37.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "configargparse" },
|
||||
@ -1245,25 +1245,26 @@ dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
{ name = "werkzeug" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d2/d1/60d5fddac2baa47314c091636868b50178a38fc71ce39d68afd847448028/locust-2.37.5.tar.gz", hash = "sha256:c90824c4cb6a01cdede220684c7c8381253fcca47fc689dbca4f6c46d740c99f", size = 2252000, upload-time = "2025-05-22T08:54:58.676Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/05/2bfdf19756c6a12f6f9513f75340ecf0595d83cab4d9fc91162225908e3d/locust-2.37.9.tar.gz", hash = "sha256:e43673b594ec5ecde4f9ba6e0d5c66c00d7c0ae93591951abe83e8d186c67175", size = 2252507, upload-time = "2025-06-05T09:26:58.186Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/a0/32a51fb48f96b0de6bb6ea7308f68b7ae1bae53e6b975672f8c4ef7f8c08/locust-2.37.5-py3-none-any.whl", hash = "sha256:9922a2718b42f1c57a05c822e47b66555b3c61292694ec5edaf7a166fac6d112", size = 2268626, upload-time = "2025-05-22T08:54:55.938Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/1c/0ece4176231c578e819d970ec08d124492833e50aafd171c582bcc414446/locust-2.37.9-py3-none-any.whl", hash = "sha256:e17da439f3a252d1fb6d4c34daf00d7e8b87e99d833a32e8a79f4f8ebb07767d", size = 2269084, upload-time = "2025-06-05T09:26:56.257Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "locust-cloud"
|
||||
version = "1.21.8"
|
||||
version = "1.23.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "configargparse" },
|
||||
{ name = "gevent" },
|
||||
{ name = "platformdirs" },
|
||||
{ name = "python-engineio" },
|
||||
{ name = "python-socketio", extra = ["client"] },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/d4/64a169b4831d26ab9dceacb192ea30c749501d87b4958e628cf1f7ef45c4/locust_cloud-1.21.8.tar.gz", hash = "sha256:e8bde0da013c8731a45cc834cdf9fec2fc21738a5f2807d93c2c5eeb3008a80e", size = 450414, upload-time = "2025-05-22T08:30:27.458Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bd/7c/d9cbbd051490aeedfbd6ddda8ad48f77dd848ee490f6ebd166d20db5911e/locust_cloud-1.23.1.tar.gz", hash = "sha256:a09161752b8c9a9205e97cef5223ee3ad967bc2d91c52d61952aaa3da6802a55", size = 450937, upload-time = "2025-06-05T06:07:53.773Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/06/76/aa8b2f73bdf7de5ee344e5d0c4749e8d62ff38257b41d9df37b0b7ac84e2/locust_cloud-1.21.8-py3-none-any.whl", hash = "sha256:4f06b5d8a26ba91840a768008f4870965b13cc71481de9797409556de2edc007", size = 407879, upload-time = "2025-05-22T08:30:25.512Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/01/5af43edee540e38ba0ee0a2e3beb72c50073e0f646bb543a8b34650315e3/locust_cloud-1.23.1-py3-none-any.whl", hash = "sha256:11677895c6ed6d0beef1b425a6f04f10ea2cfcaeaefbf00a97fb3c9134296e54", size = 408323, upload-time = "2025-06-05T06:07:51.947Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1414,40 +1415,41 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717, upload-time = "2025-02-05T03:50:34.655Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d4/38/13c2f1abae94d5ea0354e146b95a1be9b2137a0d506728e0da037c4276f6/mypy-1.16.0.tar.gz", hash = "sha256:84b94283f817e2aa6350a14b4a8fb2a35a53c286f97c9d30f53b63620e7af8ab", size = 3323139, upload-time = "2025-05-29T13:46:12.532Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433, upload-time = "2025-02-05T03:49:29.145Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472, upload-time = "2025-02-05T03:49:16.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424, upload-time = "2025-02-05T03:49:46.908Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450, upload-time = "2025-02-05T03:50:05.89Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765, upload-time = "2025-02-05T03:49:33.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701, upload-time = "2025-02-05T03:49:38.981Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338, upload-time = "2025-02-05T03:50:17.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540, upload-time = "2025-02-05T03:49:51.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051, upload-time = "2025-02-05T03:50:20.885Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751, upload-time = "2025-02-05T03:49:42.408Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783, upload-time = "2025-02-05T03:49:07.707Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618, upload-time = "2025-02-05T03:49:54.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981, upload-time = "2025-02-05T03:50:28.25Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175, upload-time = "2025-02-05T03:50:13.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675, upload-time = "2025-02-05T03:50:31.421Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020, upload-time = "2025-02-05T03:48:48.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582, upload-time = "2025-02-05T03:49:03.628Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614, upload-time = "2025-02-05T03:50:00.313Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592, upload-time = "2025-02-05T03:48:55.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611, upload-time = "2025-02-05T03:48:44.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443, upload-time = "2025-02-05T03:49:25.514Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/64/5e/a0485f0608a3d67029d3d73cec209278b025e3493a3acfda3ef3a88540fd/mypy-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7909541fef256527e5ee9c0a7e2aeed78b6cda72ba44298d1334fe7881b05c5c", size = 10967416, upload-time = "2025-05-29T13:34:17.783Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/53/5837c221f74c0d53a4bfc3003296f8179c3a2a7f336d7de7bbafbe96b688/mypy-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e71d6f0090c2256c713ed3d52711d01859c82608b5d68d4fa01a3fe30df95571", size = 10087654, upload-time = "2025-05-29T13:32:37.878Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/59/5fd2400352c3093bed4c09017fe671d26bc5bb7e6ef2d4bf85f2a2488104/mypy-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:936ccfdd749af4766be824268bfe22d1db9eb2f34a3ea1d00ffbe5b5265f5491", size = 11875192, upload-time = "2025-05-29T13:34:54.281Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/3e/4bfec74663a64c2012f3e278dbc29ffe82b121bc551758590d1b6449ec0c/mypy-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4086883a73166631307fdd330c4a9080ce24913d4f4c5ec596c601b3a4bdd777", size = 12612939, upload-time = "2025-05-29T13:33:14.766Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/1f/fecbe3dcba4bf2ca34c26ca016383a9676711907f8db4da8354925cbb08f/mypy-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:feec38097f71797da0231997e0de3a58108c51845399669ebc532c815f93866b", size = 12874719, upload-time = "2025-05-29T13:21:52.09Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/51/c2d280601cd816c43dfa512a759270d5a5ef638d7ac9bea9134c8305a12f/mypy-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:09a8da6a0ee9a9770b8ff61b39c0bb07971cda90e7297f4213741b48a0cc8d93", size = 9487053, upload-time = "2025-05-29T13:33:29.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/c4/ff2f79db7075c274fe85b5fff8797d29c6b61b8854c39e3b7feb556aa377/mypy-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9f826aaa7ff8443bac6a494cf743f591488ea940dd360e7dd330e30dd772a5ab", size = 10884498, upload-time = "2025-05-29T13:18:54.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/07/12198e83006235f10f6a7808917376b5d6240a2fd5dce740fe5d2ebf3247/mypy-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82d056e6faa508501af333a6af192c700b33e15865bda49611e3d7d8358ebea2", size = 10011755, upload-time = "2025-05-29T13:34:00.851Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/9b/5fd5801a72b5d6fb6ec0105ea1d0e01ab2d4971893076e558d4b6d6b5f80/mypy-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:089bedc02307c2548eb51f426e085546db1fa7dd87fbb7c9fa561575cf6eb1ff", size = 11800138, upload-time = "2025-05-29T13:32:55.082Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/81/a117441ea5dfc3746431e51d78a4aca569c677aa225bca2cc05a7c239b61/mypy-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6a2322896003ba66bbd1318c10d3afdfe24e78ef12ea10e2acd985e9d684a666", size = 12533156, upload-time = "2025-05-29T13:19:12.963Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/38/88ec57c6c86014d3f06251e00f397b5a7daa6888884d0abf187e4f5f587f/mypy-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:021a68568082c5b36e977d54e8f1de978baf401a33884ffcea09bd8e88a98f4c", size = 12742426, upload-time = "2025-05-29T13:20:22.72Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/53/7e9d528433d56e6f6f77ccf24af6ce570986c2d98a5839e4c2009ef47283/mypy-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:54066fed302d83bf5128632d05b4ec68412e1f03ef2c300434057d66866cea4b", size = 9478319, upload-time = "2025-05-29T13:21:17.582Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/cf/158e5055e60ca2be23aec54a3010f89dcffd788732634b344fc9cb1e85a0/mypy-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5436d11e89a3ad16ce8afe752f0f373ae9620841c50883dc96f8b8805620b13", size = 11062927, upload-time = "2025-05-29T13:35:52.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/34/cfff7a56be1609f5d10ef386342ce3494158e4d506516890142007e6472c/mypy-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f2622af30bf01d8fc36466231bdd203d120d7a599a6d88fb22bdcb9dbff84090", size = 10083082, upload-time = "2025-05-29T13:35:33.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/7f/7242062ec6288c33d8ad89574df87c3903d394870e5e6ba1699317a65075/mypy-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d045d33c284e10a038f5e29faca055b90eee87da3fc63b8889085744ebabb5a1", size = 11828306, upload-time = "2025-05-29T13:21:02.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/5f/b392f7b4f659f5b619ce5994c5c43caab3d80df2296ae54fa888b3d17f5a/mypy-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4968f14f44c62e2ec4a038c8797a87315be8df7740dc3ee8d3bfe1c6bf5dba8", size = 12702764, upload-time = "2025-05-29T13:20:42.826Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/c0/7646ef3a00fa39ac9bc0938626d9ff29d19d733011be929cfea59d82d136/mypy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb14a4a871bb8efb1e4a50360d4e3c8d6c601e7a31028a2c79f9bb659b63d730", size = 12896233, upload-time = "2025-05-29T13:18:37.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/38/52f4b808b3fef7f0ef840ee8ff6ce5b5d77381e65425758d515cdd4f5bb5/mypy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd4e1ebe126152a7bbaa4daedd781c90c8f9643c79b9748caa270ad542f12bec", size = 9565547, upload-time = "2025-05-29T13:20:02.836Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/9c/ca03bdbefbaa03b264b9318a98950a9c683e06472226b55472f96ebbc53d/mypy-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e056237c89f1587a3be1a3a70a06a698d25e2479b9a2f57325ddaaffc3567b", size = 11059753, upload-time = "2025-05-29T13:18:18.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/92/79a969b8302cfe316027c88f7dc6fee70129490a370b3f6eb11d777749d0/mypy-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b07e107affb9ee6ce1f342c07f51552d126c32cd62955f59a7db94a51ad12c0", size = 10073338, upload-time = "2025-05-29T13:19:48.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/9b/a943f09319167da0552d5cd722104096a9c99270719b1afeea60d11610aa/mypy-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6fb60cbd85dc65d4d63d37cb5c86f4e3a301ec605f606ae3a9173e5cf34997b", size = 11827764, upload-time = "2025-05-29T13:46:04.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/64/ff75e71c65a0cb6ee737287c7913ea155845a556c64144c65b811afdb9c7/mypy-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7e32297a437cc915599e0578fa6bc68ae6a8dc059c9e009c628e1c47f91495d", size = 12701356, upload-time = "2025-05-29T13:35:13.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/ad/0e93c18987a1182c350f7a5fab70550852f9fabe30ecb63bfbe51b602074/mypy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:afe420c9380ccec31e744e8baff0d406c846683681025db3531b32db56962d52", size = 12900745, upload-time = "2025-05-29T13:17:24.409Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/5d/036c278d7a013e97e33f08c047fe5583ab4f1fc47c9a49f985f1cdd2a2d7/mypy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:55f9076c6ce55dd3f8cd0c6fff26a008ca8e5131b89d5ba6d86bd3f47e736eeb", size = 9572200, upload-time = "2025-05-29T13:33:44.92Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/a3/6ed10530dec8e0fdc890d81361260c9ef1f5e5c217ad8c9b21ecb2b8366b/mypy-1.16.0-py3-none-any.whl", hash = "sha256:29e1499864a3888bca5c1542f2d7232c6e586295183320caa95758fc84034031", size = 2265773, upload-time = "2025-05-29T13:35:18.762Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1975,7 +1977,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.5"
|
||||
version = "8.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
@ -1983,23 +1985,24 @@ dependencies = [
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6", size = 1515232, upload-time = "2025-06-02T17:36:30.03Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e", size = 363797, upload-time = "2025-06-02T17:36:27.859Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-asyncio"
|
||||
version = "0.26.0"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/c4/453c52c659521066969523e87d85d54139bbd17b78f09532fb8eb8cdb58e/pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f", size = 54156, upload-time = "2025-03-25T06:22:28.883Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/d4/14f53324cb1a6381bef29d698987625d80052bb33932d8e7cbf9b337b17c/pytest_asyncio-1.0.0.tar.gz", hash = "sha256:d15463d13f4456e1ead2594520216b225a16f781e144f8fdf6c5bb4667c48b3f", size = 46960, upload-time = "2025-05-26T04:54:40.484Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694, upload-time = "2025-03-25T06:22:27.807Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/05/ce271016e351fddc8399e546f6e23761967ee09c8c568bbfbecb0c150171/pytest_asyncio-1.0.0-py3-none-any.whl", hash = "sha256:4f024da9f1ef945e680dc68610b52550e36590a67fd31bb3b4943979a1f90ef3", size = 15976, upload-time = "2025-05-26T04:54:39.035Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2017,14 +2020,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest-mock"
|
||||
version = "3.14.0"
|
||||
version = "3.14.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814, upload-time = "2024-03-21T22:14:04.964Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/28/67172c96ba684058a4d24ffe144d64783d2a270d0af0d9e792737bddc75c/pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e", size = 33241, upload-time = "2025-05-26T13:58:45.167Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863, upload-time = "2024-03-21T22:14:02.694Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/05/77b60e520511c53d1c1ca75f1930c7dd8e971d0c4379b7f4b3f9644685ba/pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0", size = 9923, upload-time = "2025-05-26T13:58:43.487Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2050,14 +2053,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "python-engineio"
|
||||
version = "4.12.0"
|
||||
version = "4.12.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "simple-websocket" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f7/e1/eee1129544b7f78fa2afa9fa0fce153cdcb21015b9b331d1b8adf90f45cb/python_engineio-4.12.0.tar.gz", hash = "sha256:f42a36a868d7063aa10ddccf6bd6117a169b6bd00d7ca53999772093b62014f9", size = 91503, upload-time = "2025-04-12T15:30:23.905Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ba/0b/67295279b66835f9fa7a491650efcd78b20321c127036eef62c11a31e028/python_engineio-4.12.2.tar.gz", hash = "sha256:e7e712ffe1be1f6a05ee5f951e72d434854a32fcfc7f6e4d9d3cae24ec70defa", size = 91677, upload-time = "2025-06-04T19:22:18.789Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/f7/0aeea75424c47633c1d98557a2323be23bed31fa950f00161b34a5150d06/python_engineio-4.12.0-py3-none-any.whl", hash = "sha256:a0c47c129c39777e8ebc6d18011efd50db2144e4e8f08983acae8a3614626535", size = 59319, upload-time = "2025-04-12T15:30:22.325Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/fa/df59acedf7bbb937f69174d00f921a7b93aa5a5f5c17d05296c814fff6fc/python_engineio-4.12.2-py3-none-any.whl", hash = "sha256:8218ab66950e179dfec4b4bbb30aecf3f5d86f5e58e6fc1aa7fde2c698b2804f", size = 59536, upload-time = "2025-06-04T19:22:16.916Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2215,16 +2218,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
version = "14.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149, upload-time = "2024-11-01T16:43:57.873Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424, upload-time = "2024-11-01T16:43:55.817Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2300,27 +2303,27 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.11.11"
|
||||
version = "0.11.13"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b2/53/ae4857030d59286924a8bdb30d213d6ff22d8f0957e738d0289990091dd8/ruff-0.11.11.tar.gz", hash = "sha256:7774173cc7c1980e6bf67569ebb7085989a78a103922fb83ef3dfe230cd0687d", size = 4186707, upload-time = "2025-05-22T19:19:34.363Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514", size = 4282054, upload-time = "2025-06-05T21:00:15.721Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/14/f2326676197bab099e2a24473158c21656fbf6a207c65f596ae15acb32b9/ruff-0.11.11-py3-none-linux_armv6l.whl", hash = "sha256:9924e5ae54125ed8958a4f7de320dab7380f6e9fa3195e3dc3b137c6842a0092", size = 10229049, upload-time = "2025-05-22T19:18:45.516Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/f3/bff7c92dd66c959e711688b2e0768e486bbca46b2f35ac319bb6cce04447/ruff-0.11.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8a93276393d91e952f790148eb226658dd275cddfde96c6ca304873f11d2ae4", size = 11053601, upload-time = "2025-05-22T19:18:49.269Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/38/8e1a3efd0ef9d8259346f986b77de0f62c7a5ff4a76563b6b39b68f793b9/ruff-0.11.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d6e333dbe2e6ae84cdedefa943dfd6434753ad321764fd937eef9d6b62022bcd", size = 10367421, upload-time = "2025-05-22T19:18:51.754Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/50/557ad9dd4fb9d0bf524ec83a090a3932d284d1a8b48b5906b13b72800e5f/ruff-0.11.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7885d9a5e4c77b24e8c88aba8c80be9255fa22ab326019dac2356cff42089fc6", size = 10581980, upload-time = "2025-05-22T19:18:54.011Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/b2/e2ed82d6e2739ece94f1bdbbd1d81b712d3cdaf69f0a1d1f1a116b33f9ad/ruff-0.11.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b5ab797fcc09121ed82e9b12b6f27e34859e4227080a42d090881be888755d4", size = 10089241, upload-time = "2025-05-22T19:18:56.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/9f/b4539f037a5302c450d7c695c82f80e98e48d0d667ecc250e6bdeb49b5c3/ruff-0.11.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e231ff3132c1119ece836487a02785f099a43992b95c2f62847d29bace3c75ac", size = 11699398, upload-time = "2025-05-22T19:18:58.248Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/fb/32e029d2c0b17df65e6eaa5ce7aea5fbeaed22dddd9fcfbbf5fe37c6e44e/ruff-0.11.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a97c9babe1d4081037a90289986925726b802d180cca784ac8da2bbbc335f709", size = 12427955, upload-time = "2025-05-22T19:19:00.981Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/e3/160488dbb11f18c8121cfd588e38095ba779ae208292765972f7732bfd95/ruff-0.11.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8c4ddcbe8a19f59f57fd814b8b117d4fcea9bee7c0492e6cf5fdc22cfa563c8", size = 12069803, upload-time = "2025-05-22T19:19:03.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/16/3b006a875f84b3d0bff24bef26b8b3591454903f6f754b3f0a318589dcc3/ruff-0.11.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6224076c344a7694c6fbbb70d4f2a7b730f6d47d2a9dc1e7f9d9bb583faf390b", size = 11242630, upload-time = "2025-05-22T19:19:05.871Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/0d/0338bb8ac0b97175c2d533e9c8cdc127166de7eb16d028a43c5ab9e75abd/ruff-0.11.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:882821fcdf7ae8db7a951df1903d9cb032bbe838852e5fc3c2b6c3ab54e39875", size = 11507310, upload-time = "2025-05-22T19:19:08.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/bf/d7130eb26174ce9b02348b9f86d5874eafbf9f68e5152e15e8e0a392e4a3/ruff-0.11.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:dcec2d50756463d9df075a26a85a6affbc1b0148873da3997286caf1ce03cae1", size = 10441144, upload-time = "2025-05-22T19:19:13.621Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/f3/4be2453b258c092ff7b1761987cf0749e70ca1340cd1bfb4def08a70e8d8/ruff-0.11.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99c28505ecbaeb6594701a74e395b187ee083ee26478c1a795d35084d53ebd81", size = 10081987, upload-time = "2025-05-22T19:19:15.821Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/6e/dfa4d2030c5b5c13db158219f2ec67bf333e8a7748dccf34cfa2a6ab9ebc/ruff-0.11.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9263f9e5aa4ff1dec765e99810f1cc53f0c868c5329b69f13845f699fe74f639", size = 11073922, upload-time = "2025-05-22T19:19:18.104Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/f4/f7b0b0c3d32b593a20ed8010fa2c1a01f2ce91e79dda6119fcc51d26c67b/ruff-0.11.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:64ac6f885e3ecb2fdbb71de2701d4e34526651f1e8503af8fb30d4915a3fe345", size = 11568537, upload-time = "2025-05-22T19:19:20.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/46/0e892064d0adc18bcc81deed9aaa9942a27fd2cd9b1b7791111ce468c25f/ruff-0.11.11-py3-none-win32.whl", hash = "sha256:1adcb9a18802268aaa891ffb67b1c94cd70578f126637118e8099b8e4adcf112", size = 10536492, upload-time = "2025-05-22T19:19:23.642Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/d9/232e79459850b9f327e9f1dc9c047a2a38a6f9689e1ec30024841fc4416c/ruff-0.11.11-py3-none-win_amd64.whl", hash = "sha256:748b4bb245f11e91a04a4ff0f96e386711df0a30412b9fe0c74d5bdc0e4a531f", size = 11612562, upload-time = "2025-05-22T19:19:27.013Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/eb/09c132cff3cc30b2e7244191dcce69437352d6d6709c0adf374f3e6f476e/ruff-0.11.11-py3-none-win_arm64.whl", hash = "sha256:6c51f136c0364ab1b774767aa8b86331bd8e9d414e2d107db7a2189f35ea1f7b", size = 10735951, upload-time = "2025-05-22T19:19:30.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2555,26 +2558,23 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.32.0.20250515"
|
||||
version = "2.32.0.20250602"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "urllib3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/c1/cdc4f9b8cfd9130fbe6276db574f114541f4231fcc6fb29648289e6e3390/types_requests-2.32.0.20250515.tar.gz", hash = "sha256:09c8b63c11318cb2460813871aaa48b671002e59fda67ca909e9883777787581", size = 23012, upload-time = "2025-05-15T03:04:31.817Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/48/b0/5321e6eeba5d59e4347fcf9bf06a5052f085c3aa0f4876230566d6a4dc97/types_requests-2.32.0.20250602.tar.gz", hash = "sha256:ee603aeefec42051195ae62ca7667cd909a2f8128fdf8aad9e8a5219ecfab3bf", size = 23042, upload-time = "2025-06-02T03:15:02.958Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/0f/68a997c73a129287785f418c1ebb6004f81e46b53b3caba88c0e03fcd04a/types_requests-2.32.0.20250515-py3-none-any.whl", hash = "sha256:f8eba93b3a892beee32643ff836993f15a785816acca21ea0ffa006f05ef0fb2", size = 20635, upload-time = "2025-05-15T03:04:30.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/18/9b782980e575c6581d5c0c1c99f4c6f89a1d7173dad072ee96b2756c02e6/types_requests-2.32.0.20250602-py3-none-any.whl", hash = "sha256:f4f335f87779b47ce10b8b8597b409130299f6971ead27fead4fe7ba6ea3e726", size = 20638, upload-time = "2025-06-02T03:15:01.959Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "types-setuptools"
|
||||
version = "76.0.0.20250313"
|
||||
version = "80.9.0.20250529"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/0f/2d1d000c2be3919bcdea15e5da48456bf1e55c18d02c5509ea59dade1408/types_setuptools-76.0.0.20250313.tar.gz", hash = "sha256:b2be66f550f95f3cad2a7d46177b273c7e9c80df7d257fa57addbbcfc8126a9e", size = 43627, upload-time = "2025-03-13T02:51:28.3Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/79/66/1b276526aad4696a9519919e637801f2c103419d2c248a6feb2729e034d1/types_setuptools-80.9.0.20250529.tar.gz", hash = "sha256:79e088ba0cba2186c8d6499cbd3e143abb142d28a44b042c28d3148b1e353c91", size = 41337, upload-time = "2025-05-29T03:07:34.487Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/89/ea9669a0a76b160ffb312d0b02b15bad053c1bc81d2a54e42e3a402ca754/types_setuptools-76.0.0.20250313-py3-none-any.whl", hash = "sha256:bf454b2a49b8cfd7ebcf5844d4dd5fe4c8666782df1e3663c5866fd51a47460e", size = 65845, upload-time = "2025-03-13T02:51:27.055Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/d8/83790d67ec771bf029a45ff1bd1aedbb738d8aa58c09dd0cc3033eea0e69/types_setuptools-80.9.0.20250529-py3-none-any.whl", hash = "sha256:00dfcedd73e333a430e10db096e4d46af93faf9314f832f13b6bbe3d6757e95f", size = 63263, upload-time = "2025-05-29T03:07:33.064Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2627,16 +2627,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.34.2"
|
||||
version = "0.34.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815, upload-time = "2025-04-19T06:02:50.101Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483, upload-time = "2025-04-19T06:02:48.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
|
2
mobile/.gitignore
vendored
2
mobile/.gitignore
vendored
@ -59,4 +59,4 @@ libisar.so
|
||||
.fvm/
|
||||
|
||||
# Translation file
|
||||
lib/generated/codegen_loader.g.dart
|
||||
lib/generated/
|
@ -17,6 +17,27 @@ To add a new translation text, enter the key-value pair in the `i18n/en.json` in
|
||||
make translation
|
||||
```
|
||||
|
||||
## Static Analysis
|
||||
|
||||
The following checks of static analysis must pass for a contribution to the mobile app to be valid:
|
||||
|
||||
```bash
|
||||
dart format lib
|
||||
dart analyze
|
||||
dart run custom_lint
|
||||
dcm analyze lib
|
||||
```
|
||||
|
||||
[DCM](https://dcm.dev/) is a vendor tool that needs to be downloaded manually to run locally.
|
||||
Immich was provided an open source license.
|
||||
To use it, it is important that you do not have an active free tier license (can be verified with `dcm license`).
|
||||
If you have write-access to the Immich repository directly, running dcm in your clone should just work.
|
||||
If you are working on a clone of a fork, you need to connect to the main Immich repository as remote first:
|
||||
|
||||
```bash
|
||||
git remote add immich git@github.com:immich-app/immich.git
|
||||
```
|
||||
|
||||
## Immich-Flutter Directory Structure
|
||||
|
||||
Below are the directory inside the `lib` directory:
|
||||
|
@ -128,82 +128,169 @@ custom_lint:
|
||||
- test/**.dart
|
||||
|
||||
dart_code_metrics:
|
||||
extends:
|
||||
- recommended
|
||||
rules:
|
||||
# Common
|
||||
- arguments-ordering:
|
||||
last:
|
||||
- child
|
||||
- children
|
||||
- avoid-accessing-other-classes-private-members
|
||||
- avoid-assigning-to-static-field
|
||||
- avoid-assignments-as-conditions
|
||||
- avoid-async-call-in-sync-function
|
||||
- avoid-collapsible-if
|
||||
- avoid-collection-equality-checks
|
||||
- avoid-complex-loop-conditions
|
||||
- avoid-declaring-call-method
|
||||
- avoid-extensions-on-records
|
||||
- avoid-function-type-in-records
|
||||
- avoid-future-ignore
|
||||
- avoid-global-state
|
||||
- avoid-inverted-boolean-checks
|
||||
- avoid-late-final-reassignment
|
||||
- avoid-local-functions:
|
||||
exclude:
|
||||
- test/**.dart
|
||||
- avoid-negated-conditions
|
||||
- avoid-nested-streams-and-futures
|
||||
- avoid-referencing-subclasses
|
||||
- avoid-unnecessary-continue
|
||||
- avoid-unnecessary-nullable-return-type: false
|
||||
- binary-expression-operand-order
|
||||
- pattern-fields-ordering
|
||||
- prefer-abstract-final-static-class
|
||||
- prefer-commenting-future-delayed
|
||||
- prefer-early-return
|
||||
- prefer-first
|
||||
- prefer-immediate-return
|
||||
- prefer-last
|
||||
- prefer-simpler-boolean-expressions
|
||||
- prefer-switch-expression
|
||||
- prefer-type-over-var
|
||||
- use-existing-destructuring
|
||||
- use-existing-variable
|
||||
# Flutter
|
||||
- avoid-border-all
|
||||
- avoid-complex-arithmetic-expressions
|
||||
- avoid-expanded-as-spacer
|
||||
- avoid-if-with-many-branches
|
||||
- avoid-inherited-widget-in-initstate
|
||||
- avoid-late-context
|
||||
- avoid-returning-widgets
|
||||
- avoid-shrink-wrap-in-lists
|
||||
- avoid-single-child-column-or-row
|
||||
- avoid-stateless-widget-initialized-fields
|
||||
- avoid-wrapping-in-padding
|
||||
- prefer-align-over-container
|
||||
- prefer-const-border-radius
|
||||
- prefer-correct-callback-field-name: false
|
||||
- prefer-correct-edge-insets-constructor
|
||||
- prefer-define-hero-tag
|
||||
- prefer-extracting-callbacks
|
||||
- prefer-for-loop-in-children
|
||||
- prefer-match-file-name: false
|
||||
- prefer-sliver-prefix
|
||||
- prefer-spacing
|
||||
- prefer-text-rich
|
||||
- prefer-transform-over-container
|
||||
- prefer-using-list-view
|
||||
- prefer-widget-private-members:
|
||||
ignore-static: true
|
||||
- use-closest-build-context
|
||||
# riverpod
|
||||
- avoid-calling-notifier-members-inside-build
|
||||
- avoid-notifier-constructors
|
||||
- avoid-ref-read-inside-build
|
||||
- avoid-ref-watch-outside-build
|
||||
- avoid-unnecessary-consumer-widgets
|
||||
- dispose-provided-instances
|
||||
- use-ref-read-synchronously
|
||||
# All rules from "recommended" preset
|
||||
# Show potential errors
|
||||
# - avoid-cascade-after-if-null
|
||||
# - avoid-collection-methods-with-unrelated-types
|
||||
# - avoid-duplicate-exports
|
||||
# - avoid-dynamic
|
||||
# - avoid-missing-enum-constant-in-map
|
||||
# - avoid-passing-async-when-sync-expected
|
||||
# - avoid-throw-in-catch-block
|
||||
- avoid-unused-parameters
|
||||
# - avoid-unnecessary-type-assertions
|
||||
# - avoid-unnecessary-type-casts
|
||||
# - avoid-unrelated-type-assertions
|
||||
# - avoid-unrelated-type-casts
|
||||
# - no-empty-block
|
||||
# - no-equal-then-else
|
||||
# - prefer-correct-test-file-name
|
||||
# - prefer-match-file-name
|
||||
# - prefer-return-await
|
||||
# - avoid-self-assignment
|
||||
# - avoid-self-compare
|
||||
# - avoid-shadowing
|
||||
# - prefer-iterable-of
|
||||
# - no-equal-switch-case
|
||||
# - no-equal-conditions
|
||||
# - avoid-equal-expressions
|
||||
# - avoid-missed-calls
|
||||
# - avoid-unnecessary-negations
|
||||
# - avoid-unused-generics
|
||||
# - function-always-returns-null
|
||||
# - avoid-throw-objects-without-tostring
|
||||
# - avoid-unsafe-collection-methods
|
||||
# - prefer-wildcard-pattern
|
||||
# - no-equal-switch-expression-cases
|
||||
# - avoid-future-tostring
|
||||
# - avoid-unassigned-late-fields
|
||||
# - avoid-nested-futures
|
||||
# - avoid-generics-shadowing
|
||||
# - prefer-parentheses-with-if-null
|
||||
# - no-equal-nested-conditions
|
||||
# - avoid-shadowed-extension-methods
|
||||
# - avoid-unnecessary-conditionals
|
||||
# - avoid-double-slash-imports
|
||||
# - avoid-map-keys-contains
|
||||
# - prefer-correct-json-casts
|
||||
# - avoid-duplicate-mixins
|
||||
# - avoid-nullable-interpolation
|
||||
# - avoid-unused-instances
|
||||
# - prefer-correct-for-loop-increment
|
||||
# - prefer-public-exception-classes
|
||||
# - avoid-uncaught-future-errors
|
||||
# - always-remove-listener
|
||||
# - avoid-unnecessary-setstate
|
||||
# - check-for-equals-in-render-object-setters
|
||||
# - consistent-update-render-object
|
||||
# - use-setstate-synchronously
|
||||
# - avoid-incomplete-copy-with
|
||||
# - proper-super-calls
|
||||
# - dispose-fields
|
||||
# - avoid-empty-setstate
|
||||
# - avoid-state-constructors
|
||||
# - avoid-recursive-widget-calls
|
||||
# - avoid-missing-image-alt
|
||||
# - avoid-passing-self-as-argument
|
||||
# - avoid-unnecessary-if
|
||||
# - avoid-unconditional-break
|
||||
# - avoid-referencing-discarded-variables
|
||||
# - avoid-unnecessary-local-late
|
||||
# - avoid-wildcard-cases-with-enums
|
||||
# - match-getter-setter-field-names
|
||||
# - avoid-accessing-collections-by-constant-index
|
||||
# - prefer-unique-test-names
|
||||
# - avoid-duplicate-cascades
|
||||
# - prefer-specific-cases-first
|
||||
# - avoid-duplicate-switch-case-conditions
|
||||
# - prefer-explicit-function-type
|
||||
# - avoid-misused-test-matchers
|
||||
# - avoid-duplicate-test-assertions
|
||||
# - prefer-switch-with-enums
|
||||
# - prefer-any-or-every
|
||||
# - avoid-duplicate-map-keys
|
||||
# - avoid-nullable-tostring
|
||||
# - avoid-undisposed-instances
|
||||
# - avoid-duplicate-initializers
|
||||
# - avoid-unassigned-stream-subscriptions
|
||||
# - avoid-empty-test-groups
|
||||
# - avoid-not-encodable-in-to-json
|
||||
# - avoid-contradictory-expressions
|
||||
# - avoid-excessive-expressions
|
||||
# - prefer-private-extension-type-field
|
||||
# - avoid-renaming-representation-getters
|
||||
# - avoid-empty-spread
|
||||
# - avoid-unnecessary-gesture-detector
|
||||
# - avoid-missing-completer-stack-trace
|
||||
# - avoid-casting-to-extension-type
|
||||
# - prefer-overriding-parent-equality
|
||||
# - avoid-missing-controller
|
||||
# - avoid-unknown-pragma
|
||||
# - avoid-conditions-with-boolean-literals
|
||||
# - avoid-multi-assignment
|
||||
# - avoid-collection-equality-checks
|
||||
# - avoid-only-rethrow
|
||||
# - avoid-incorrect-image-opacity
|
||||
# - avoid-misused-set-literals
|
||||
# - dispose-class-fields
|
||||
# - avoid-suspicious-super-overrides
|
||||
# - avoid-assignments-as-conditions
|
||||
# - avoid-unused-assignment
|
||||
# - avoid-unnecessary-overrides
|
||||
# - avoid-implicitly-nullable-extension-types
|
||||
# Enable with the next release
|
||||
# - avoid-late-final-reassignment
|
||||
# - avoid-duplicate-constant-values
|
||||
# - function-always-returns-same-value
|
||||
# - avoid-flexible-outside-flex
|
||||
# - avoid-unnecessary-patterns
|
||||
# - use-closest-build-context
|
||||
# - avoid-commented-out-code
|
||||
# - avoid-recursive-tostring
|
||||
# - avoid-enum-values-by-index
|
||||
# - avoid-constant-assert-conditions
|
||||
# - avoid-inconsistent-digit-separators
|
||||
# - pass-existing-future-to-future-builder
|
||||
# - pass-existing-stream-to-stream-builder
|
||||
|
||||
# Code simplification
|
||||
# - avoid-redundant-async
|
||||
# - avoid-redundant-else
|
||||
# - avoid-unnecessary-nullable-return-type
|
||||
# - avoid-redundant-pragma-inline
|
||||
# - avoid-nested-records
|
||||
# - avoid-redundant-positional-field-name
|
||||
# - avoid-explicit-pattern-field-name
|
||||
# - prefer-simpler-patterns-null-check
|
||||
# - avoid-unnecessary-return
|
||||
# - avoid-duplicate-patterns
|
||||
# - avoid-keywords-in-wildcard-pattern
|
||||
# - avoid-unnecessary-futures
|
||||
# - avoid-unnecessary-reassignment
|
||||
# - avoid-unnecessary-call
|
||||
# - avoid-unnecessary-stateful-widgets
|
||||
# - prefer-dedicated-media-query-methods
|
||||
# - avoid-unnecessary-overrides-in-state
|
||||
# - move-variable-closer-to-its-usage
|
||||
# - avoid-nullable-parameters-with-default-values
|
||||
# - prefer-null-aware-spread
|
||||
# - avoid-inferrable-type-arguments
|
||||
# - avoid-unnecessary-super
|
||||
# - avoid-unnecessary-collections
|
||||
# - avoid-unnecessary-extends
|
||||
# - avoid-unnecessary-enum-arguments
|
||||
# - prefer-contains
|
||||
# Enable with the next release
|
||||
# - prefer-simpler-boolean-expressions
|
||||
# - prefer-spacing
|
||||
# - avoid-unnecessary-continue
|
||||
# - avoid-unnecessary-compare-to
|
||||
|
||||
# Style
|
||||
# - prefer-trailing-comma
|
||||
# - unnecessary-trailing-comma
|
||||
# - prefer-declaring-const-constructor
|
||||
# - prefer-single-widget-per-file
|
||||
# - prefer-prefixed-global-constants
|
||||
# - prefer-correct-callback-field-name
|
||||
|
@ -29,6 +29,7 @@ if (keystorePropertiesFile.exists()) {
|
||||
|
||||
android {
|
||||
compileSdkVersion 35
|
||||
ndkVersion = "28.1.13356709"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
|
@ -85,6 +85,8 @@ data class PlatformAsset (
|
||||
val type: Long,
|
||||
val createdAt: Long? = null,
|
||||
val updatedAt: Long? = null,
|
||||
val width: Long? = null,
|
||||
val height: Long? = null,
|
||||
val durationInSeconds: Long
|
||||
)
|
||||
{
|
||||
@ -95,8 +97,10 @@ data class PlatformAsset (
|
||||
val type = pigeonVar_list[2] as Long
|
||||
val createdAt = pigeonVar_list[3] as Long?
|
||||
val updatedAt = pigeonVar_list[4] as Long?
|
||||
val durationInSeconds = pigeonVar_list[5] as Long
|
||||
return PlatformAsset(id, name, type, createdAt, updatedAt, durationInSeconds)
|
||||
val width = pigeonVar_list[5] as Long?
|
||||
val height = pigeonVar_list[6] as Long?
|
||||
val durationInSeconds = pigeonVar_list[7] as Long
|
||||
return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
@ -106,6 +110,8 @@ data class PlatformAsset (
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
)
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
MediaStore.MediaColumns.DATE_MODIFIED,
|
||||
MediaStore.Files.FileColumns.MEDIA_TYPE,
|
||||
MediaStore.MediaColumns.BUCKET_ID,
|
||||
MediaStore.MediaColumns.WIDTH,
|
||||
MediaStore.MediaColumns.HEIGHT,
|
||||
MediaStore.MediaColumns.DURATION
|
||||
)
|
||||
|
||||
@ -68,6 +70,8 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
val dateModifiedColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED)
|
||||
val mediaTypeColumn = c.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE)
|
||||
val bucketIdColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.BUCKET_ID)
|
||||
val widthColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.WIDTH)
|
||||
val heightColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.HEIGHT)
|
||||
val durationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION)
|
||||
|
||||
while (c.moveToNext()) {
|
||||
@ -86,12 +90,23 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
?: c.getLong(dateAddedColumn)
|
||||
// Date modified is seconds since epoch
|
||||
val modifiedAt = c.getLong(dateModifiedColumn)
|
||||
val width = c.getInt(widthColumn).toLong()
|
||||
val height = c.getInt(heightColumn).toLong()
|
||||
// Duration is milliseconds
|
||||
val duration = if (mediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) 0
|
||||
else c.getLong(durationColumn) / 1000
|
||||
val bucketId = c.getString(bucketIdColumn)
|
||||
|
||||
val asset = PlatformAsset(id, name, mediaType.toLong(), createdAt, modifiedAt, duration)
|
||||
val asset = PlatformAsset(
|
||||
id,
|
||||
name,
|
||||
mediaType.toLong(),
|
||||
createdAt,
|
||||
modifiedAt,
|
||||
width,
|
||||
height,
|
||||
duration
|
||||
)
|
||||
yield(AssetResult.ValidAsset(asset, bucketId))
|
||||
}
|
||||
}
|
||||
|
63
mobile/bin/generate_keys.dart
Normal file
63
mobile/bin/generate_keys.dart
Normal file
@ -0,0 +1,63 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const _kReservedWords = ['continue'];
|
||||
|
||||
void main() async {
|
||||
final sourceFile = File('../i18n/en.json');
|
||||
if (!await sourceFile.exists()) {
|
||||
stderr.writeln('Source file does not exist');
|
||||
return;
|
||||
}
|
||||
|
||||
final outputDir = Directory('lib/generated');
|
||||
await outputDir.create(recursive: true);
|
||||
|
||||
final outputFile = File('lib/generated/intl_keys.g.dart');
|
||||
await _generate(sourceFile, outputFile);
|
||||
print('Generated ${outputFile.path}');
|
||||
}
|
||||
|
||||
Future<void> _generate(File source, File output) async {
|
||||
final content = await source.readAsString();
|
||||
final translations = json.decode(content) as Map<String, dynamic>;
|
||||
|
||||
final buffer = StringBuffer('''
|
||||
// DO NOT EDIT. This is code generated via generate_keys.dart
|
||||
|
||||
abstract class IntlKeys {
|
||||
''');
|
||||
|
||||
_writeKeys(buffer, translations);
|
||||
buffer.writeln('}');
|
||||
|
||||
await output.writeAsString(buffer.toString());
|
||||
}
|
||||
|
||||
void _writeKeys(
|
||||
StringBuffer buffer,
|
||||
Map<String, dynamic> map, [
|
||||
String prefix = '',
|
||||
]) {
|
||||
for (final entry in map.entries) {
|
||||
final key = entry.key;
|
||||
final value = entry.value;
|
||||
|
||||
if (value is Map<String, dynamic>) {
|
||||
_writeKeys(buffer, value, prefix.isEmpty ? key : '${prefix}_$key');
|
||||
} else {
|
||||
final name = _cleanName(prefix.isEmpty ? key : '${prefix}_$key');
|
||||
final path = prefix.isEmpty ? key : '$prefix.$key'.replaceAll('_', '.');
|
||||
buffer.writeln(' static const $name = \'$path\';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _cleanName(String name) {
|
||||
name = name.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_');
|
||||
if (RegExp(r'^[0-9]').hasMatch(name)) name = 'k_$name';
|
||||
if (_kReservedWords.contains(name)) name = '${name}_';
|
||||
return name;
|
||||
}
|
1
mobile/dcm_global.yaml
Normal file
1
mobile/dcm_global.yaml
Normal file
@ -0,0 +1 @@
|
||||
version: '>=1.29.0 <1.30.0'
|
2
mobile/drift_schemas/main/drift_schema_v1.json
generated
2
mobile/drift_schemas/main/drift_schema_v1.json
generated
File diff suppressed because one or more lines are too long
@ -189,10 +189,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: lints
|
||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "6.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -362,4 +362,4 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
dart: ">=3.8.0-0 <4.0.0"
|
||||
|
@ -11,4 +11,4 @@ dependencies:
|
||||
glob: ^2.1.2
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^5.0.0
|
||||
lints: ^6.0.0
|
||||
|
@ -1,6 +1,9 @@
|
||||
PODS:
|
||||
- background_downloader (0.0.1):
|
||||
- Flutter
|
||||
- bonsoir_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
@ -64,10 +67,10 @@ PODS:
|
||||
- local_auth_darwin (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- MapLibre (6.5.0)
|
||||
- MapLibre (6.14.0)
|
||||
- maplibre_gl (0.0.1):
|
||||
- Flutter
|
||||
- MapLibre (= 6.5.0)
|
||||
- MapLibre (= 6.14.0)
|
||||
- native_video_player (1.0.0):
|
||||
- Flutter
|
||||
- network_info_plus (0.0.1):
|
||||
@ -129,6 +132,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- background_downloader (from `.symlinks/plugins/background_downloader/ios`)
|
||||
- bonsoir_darwin (from `.symlinks/plugins/bonsoir_darwin/darwin`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
@ -173,6 +177,8 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
background_downloader:
|
||||
:path: ".symlinks/plugins/background_downloader/ios"
|
||||
bonsoir_darwin:
|
||||
:path: ".symlinks/plugins/bonsoir_darwin/darwin"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
@ -236,6 +242,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
|
||||
bonsoir_darwin: 29c7ccf356646118844721f36e1de4b61f6cbd0e
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
@ -253,8 +260,8 @@ SPEC CHECKSUMS:
|
||||
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
|
||||
isar_flutter_libs: bc909e72c3d756c2759f14c8776c13b5b0556e26
|
||||
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
|
||||
MapLibre: 0ebfa9329d313cec8bf0a5ba5a336a1dc903785e
|
||||
maplibre_gl: eab61cca6e1cfa9187249bacd3f08b51e8cd8ae9
|
||||
MapLibre: 69e572367f4ef6287e18246cfafc39c80cdcabcd
|
||||
maplibre_gl: 3c924e44725147b03dda33430ad216005b40555f
|
||||
native_video_player: b65c58951ede2f93d103a25366bdebca95081265
|
||||
network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
|
@ -113,6 +113,11 @@
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true />
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_googlecast._tcp</string>
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
@ -164,4 +169,4 @@
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||
|
@ -135,6 +135,8 @@ struct PlatformAsset: Hashable {
|
||||
var type: Int64
|
||||
var createdAt: Int64? = nil
|
||||
var updatedAt: Int64? = nil
|
||||
var width: Int64? = nil
|
||||
var height: Int64? = nil
|
||||
var durationInSeconds: Int64
|
||||
|
||||
|
||||
@ -145,7 +147,9 @@ struct PlatformAsset: Hashable {
|
||||
let type = pigeonVar_list[2] as! Int64
|
||||
let createdAt: Int64? = nilOrValue(pigeonVar_list[3])
|
||||
let updatedAt: Int64? = nilOrValue(pigeonVar_list[4])
|
||||
let durationInSeconds = pigeonVar_list[5] as! Int64
|
||||
let width: Int64? = nilOrValue(pigeonVar_list[5])
|
||||
let height: Int64? = nilOrValue(pigeonVar_list[6])
|
||||
let durationInSeconds = pigeonVar_list[7] as! Int64
|
||||
|
||||
return PlatformAsset(
|
||||
id: id,
|
||||
@ -153,6 +157,8 @@ struct PlatformAsset: Hashable {
|
||||
type: type,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds
|
||||
)
|
||||
}
|
||||
@ -163,6 +169,8 @@ struct PlatformAsset: Hashable {
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
]
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ extension PHAsset {
|
||||
type: Int64(mediaType.rawValue),
|
||||
createdAt: creationDate.map { Int64($0.timeIntervalSince1970) },
|
||||
updatedAt: modificationDate.map { Int64($0.timeIntervalSince1970) },
|
||||
width: Int64(pixelWidth),
|
||||
height: Int64(pixelHeight),
|
||||
durationInSeconds: Int64(duration)
|
||||
)
|
||||
}
|
||||
@ -156,8 +158,6 @@ class NativeSyncApiImpl: NativeSyncApi {
|
||||
id: asset.localIdentifier,
|
||||
name: "",
|
||||
type: 0,
|
||||
createdAt: nil,
|
||||
updatedAt: nil,
|
||||
durationInSeconds: 0
|
||||
)
|
||||
if (updatedAssets.contains(AssetWrapper(with: predicate))) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
List<ColorFilter> filters = [
|
||||
const List<ColorFilter> filters = [
|
||||
//Original
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
@ -25,7 +25,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Vintage
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.8,
|
||||
0.1,
|
||||
0.1,
|
||||
@ -48,7 +48,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Mood
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.1,
|
||||
0.1,
|
||||
@ -71,7 +71,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Crisp
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
@ -94,7 +94,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Cool
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0,
|
||||
0.2,
|
||||
@ -117,7 +117,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Blush
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0.1,
|
||||
0.1,
|
||||
@ -140,7 +140,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Sunkissed
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0,
|
||||
0.1,
|
||||
@ -163,7 +163,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Fresh
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
@ -186,7 +186,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Classic
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0,
|
||||
-0.1,
|
||||
@ -209,7 +209,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Lomo-ish
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.5,
|
||||
0,
|
||||
0.1,
|
||||
@ -232,7 +232,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Nashville
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.15,
|
||||
-0.15,
|
||||
@ -255,7 +255,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Valencia
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.15,
|
||||
0.1,
|
||||
0.1,
|
||||
@ -278,7 +278,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Clarendon
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
@ -301,7 +301,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Moon
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.33,
|
||||
0.33,
|
||||
0.33,
|
||||
@ -324,7 +324,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Willow
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
@ -347,7 +347,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Kodak
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0.1,
|
||||
-0.1,
|
||||
@ -370,7 +370,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Frost
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.8,
|
||||
0.2,
|
||||
0.1,
|
||||
@ -393,7 +393,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Night Vision
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.1,
|
||||
0.95,
|
||||
0.2,
|
||||
@ -416,7 +416,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Sunset
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.5,
|
||||
0.2,
|
||||
0,
|
||||
@ -439,7 +439,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Noir
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
-0.3,
|
||||
0.1,
|
||||
@ -462,7 +462,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Dreamy
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0.1,
|
||||
0.1,
|
||||
@ -485,7 +485,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Sepia
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.393,
|
||||
0.769,
|
||||
0.189,
|
||||
@ -508,7 +508,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Radium
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.438,
|
||||
-0.062,
|
||||
-0.062,
|
||||
@ -531,7 +531,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Aqua
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.2126,
|
||||
0.7152,
|
||||
0.0722,
|
||||
@ -554,7 +554,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Purple Haze
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0,
|
||||
1.2,
|
||||
@ -577,7 +577,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Lemonade
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.1,
|
||||
0,
|
||||
@ -600,7 +600,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Caramel
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.6,
|
||||
0.2,
|
||||
0,
|
||||
@ -623,7 +623,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Peachy
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0.5,
|
||||
0,
|
||||
@ -646,7 +646,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Neon
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
@ -669,7 +669,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Cold Morning
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0.1,
|
||||
0.2,
|
||||
@ -692,7 +692,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Lush
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0.2,
|
||||
0,
|
||||
@ -715,7 +715,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Urban Neon
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0,
|
||||
0.3,
|
||||
@ -738,7 +738,7 @@ List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Monochrome
|
||||
const ColorFilter.matrix([
|
||||
ColorFilter.matrix([
|
||||
0.6,
|
||||
0.2,
|
||||
0.2,
|
||||
|
@ -3,11 +3,11 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||
|
||||
abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
|
||||
Future<List<LocalAlbum>> getAll({SortLocalAlbumsBy? sortBy});
|
||||
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}});
|
||||
|
||||
Future<List<LocalAsset>> getAssetsForAlbum(String albumId);
|
||||
Future<List<LocalAsset>> getAssets(String albumId);
|
||||
|
||||
Future<List<String>> getAssetIdsForAlbum(String albumId);
|
||||
Future<List<String>> getAssetIds(String albumId);
|
||||
|
||||
Future<void> upsert(
|
||||
LocalAlbum album, {
|
||||
@ -26,12 +26,9 @@ abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
|
||||
required Map<String, List<String>> assetAlbums,
|
||||
});
|
||||
|
||||
Future<void> syncAlbumDeletes(
|
||||
String albumId,
|
||||
Iterable<String> assetIdsToKeep,
|
||||
);
|
||||
Future<void> syncDeletes(String albumId, Iterable<String> assetIdsToKeep);
|
||||
|
||||
Future<List<LocalAsset>> getAssetsToHash(String albumId);
|
||||
}
|
||||
|
||||
enum SortLocalAlbumsBy { id }
|
||||
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
||||
|
@ -6,9 +6,11 @@ abstract interface class IStoreRepository implements IDatabaseRepository {
|
||||
|
||||
Future<T?> tryGet<T>(StoreKey<T> key);
|
||||
|
||||
Future<List<StoreDto<Object>>> getAll();
|
||||
|
||||
Stream<T?> watch<T>(StoreKey<T> key);
|
||||
|
||||
Stream<StoreUpdateEvent> watchAll();
|
||||
Stream<StoreDto<Object>> watchAll();
|
||||
|
||||
Future<bool> update<T>(StoreKey<T> key, T value);
|
||||
|
||||
|
@ -15,4 +15,13 @@ abstract interface class ISyncStreamRepository implements IDatabaseRepository {
|
||||
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data);
|
||||
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data);
|
||||
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data);
|
||||
|
||||
Future<void> updateAlbumsV1(Iterable<SyncAlbumV1> data);
|
||||
Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data);
|
||||
|
||||
// Future<void> updateAlbumAssetsV1(Iterable<SyncAlbumAssetV1> data);
|
||||
// Future<void> deleteAlbumAssetsV1(Iterable<SyncAlbumAssetV1> data);
|
||||
|
||||
Future<void> updateAlbumUsersV1(Iterable<SyncAlbumUserV1> data);
|
||||
Future<void> deleteAlbumUsersV1(Iterable<SyncAlbumUserDeleteV1> data);
|
||||
}
|
||||
|
68
mobile/lib/domain/models/album/album.model.dart
Normal file
68
mobile/lib/domain/models/album/album.model.dart
Normal file
@ -0,0 +1,68 @@
|
||||
enum AssetOrder {
|
||||
// do not change this order!
|
||||
asc,
|
||||
desc,
|
||||
}
|
||||
|
||||
// Model for an album stored in the server
|
||||
class Album {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final String? thumbnailAssetId;
|
||||
final bool isActivityEnabled;
|
||||
final AssetOrder order;
|
||||
|
||||
const Album({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.thumbnailAssetId,
|
||||
required this.isActivityEnabled,
|
||||
required this.order,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''Album {
|
||||
id: $id,
|
||||
name: $name,
|
||||
description: $description,
|
||||
createdAt: $createdAt,
|
||||
updatedAt: $updatedAt,
|
||||
isActivityEnabled: $isActivityEnabled,
|
||||
order: $order,
|
||||
thumbnailAssetId: ${thumbnailAssetId ?? "<NA>"}
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is! Album) return false;
|
||||
if (identical(this, other)) return true;
|
||||
return id == other.id &&
|
||||
name == other.name &&
|
||||
description == other.description &&
|
||||
createdAt == other.createdAt &&
|
||||
updatedAt == other.updatedAt &&
|
||||
thumbnailAssetId == other.thumbnailAssetId &&
|
||||
isActivityEnabled == other.isActivityEnabled &&
|
||||
order == other.order;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return id.hashCode ^
|
||||
name.hashCode ^
|
||||
description.hashCode ^
|
||||
createdAt.hashCode ^
|
||||
updatedAt.hashCode ^
|
||||
thumbnailAssetId.hashCode ^
|
||||
isActivityEnabled.hashCode ^
|
||||
order.hashCode;
|
||||
}
|
||||
}
|
5
mobile/lib/domain/models/album_user.model.dart
Normal file
5
mobile/lib/domain/models/album_user.model.dart
Normal file
@ -0,0 +1,5 @@
|
||||
enum AlbumUserRole {
|
||||
// do not change this order!
|
||||
editor,
|
||||
viewer,
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
enum BackupSelection {
|
||||
none._(1),
|
||||
selected._(0),
|
||||
excluded._(2);
|
||||
|
||||
// Used to sort albums based on the backupSelection
|
||||
// selected -> none -> excluded
|
||||
final int sortOrder;
|
||||
const BackupSelection._(this.sortOrder);
|
||||
// Do not change the order of these values
|
||||
selected,
|
||||
none,
|
||||
excluded,
|
||||
}
|
||||
|
||||
class LocalAlbum {
|
||||
|
@ -76,23 +76,23 @@ enum StoreKey<T> {
|
||||
Type get type => T;
|
||||
}
|
||||
|
||||
class StoreUpdateEvent<T> {
|
||||
class StoreDto<T> {
|
||||
final StoreKey<T> key;
|
||||
final T? value;
|
||||
|
||||
const StoreUpdateEvent(this.key, this.value);
|
||||
const StoreDto(this.key, this.value);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''
|
||||
StoreUpdateEvent: {
|
||||
StoreDto: {
|
||||
key: $key,
|
||||
value: ${value ?? '<NA>'},
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant StoreUpdateEvent<T> other) {
|
||||
bool operator ==(covariant StoreDto<T> other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.key == key && other.value == value;
|
||||
|
@ -2,8 +2,7 @@ import 'package:openapi/api.dart';
|
||||
|
||||
class SyncEvent {
|
||||
final SyncEntityType type;
|
||||
// ignore: avoid-dynamic
|
||||
final dynamic data;
|
||||
final Object data;
|
||||
final String ack;
|
||||
|
||||
const SyncEvent({required this.type, required this.data, required this.ack});
|
||||
|
@ -33,18 +33,12 @@ class HashService {
|
||||
Future<void> hashAssets() async {
|
||||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
// Sorted by backupSelection followed by isCloud
|
||||
final localAlbums = await _localAlbumRepository.getAll();
|
||||
localAlbums.sort((a, b) {
|
||||
final backupComparison =
|
||||
a.backupSelection.sortOrder.compareTo(b.backupSelection.sortOrder);
|
||||
|
||||
if (backupComparison != 0) {
|
||||
return backupComparison;
|
||||
}
|
||||
|
||||
// Local albums come before iCloud albums
|
||||
return (a.isIosSharedAlbum ? 1 : 0).compareTo(b.isIosSharedAlbum ? 1 : 0);
|
||||
});
|
||||
final localAlbums = await _localAlbumRepository.getAll(
|
||||
sortBy: {
|
||||
SortLocalAlbumsBy.backupSelection,
|
||||
SortLocalAlbumsBy.isIosSharedAlbum,
|
||||
},
|
||||
);
|
||||
|
||||
for (final album in localAlbums) {
|
||||
final assetsToHash =
|
||||
@ -96,13 +90,18 @@ class HashService {
|
||||
final hashed = <LocalAsset>[];
|
||||
final hashes =
|
||||
await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
|
||||
assert(
|
||||
hashes.length == toHash.length,
|
||||
"Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}",
|
||||
);
|
||||
|
||||
for (final (index, hash) in hashes.indexed) {
|
||||
final asset = toHash[index].asset;
|
||||
for (int i = 0; i < hashes.length; i++) {
|
||||
final hash = hashes[i];
|
||||
final asset = toHash[i].asset;
|
||||
if (hash?.length == 20) {
|
||||
hashed.add(asset.copyWith(checksum: base64.encode(hash!)));
|
||||
} else {
|
||||
_log.warning("Failed to hash file ${asset.id}");
|
||||
_log.warning("Failed to hash file for ${asset.id}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ class LocalSyncService {
|
||||
if (_platform.isAndroid) {
|
||||
for (final album in dbAlbums) {
|
||||
final deviceIds = await _nativeSyncApi.getAssetIdsForAlbum(album.id);
|
||||
await _localAlbumRepository.syncAlbumDeletes(album.id, deviceIds);
|
||||
await _localAlbumRepository.syncDeletes(album.id, deviceIds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ class LocalSyncService {
|
||||
}
|
||||
|
||||
final dbAlbums =
|
||||
await _localAlbumRepository.getAll(sortBy: SortLocalAlbumsBy.id);
|
||||
await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
|
||||
|
||||
await diffSortedLists(
|
||||
dbAlbums,
|
||||
@ -252,7 +252,7 @@ class LocalSyncService {
|
||||
.then((a) => a.toLocalAssets())
|
||||
: <LocalAsset>[];
|
||||
final assetsInDb = dbAlbum.assetCount > 0
|
||||
? await _localAlbumRepository.getAssetsForAlbum(dbAlbum.id)
|
||||
? await _localAlbumRepository.getAssets(dbAlbum.id)
|
||||
: <LocalAsset>[];
|
||||
|
||||
if (deviceAlbum.assetCount == 0) {
|
||||
@ -373,6 +373,8 @@ extension on Iterable<PlatformAsset> {
|
||||
updatedAt: e.updatedAt == null
|
||||
? DateTime.now()
|
||||
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
|
||||
width: e.width,
|
||||
height: e.height,
|
||||
durationInSeconds: e.durationInSeconds,
|
||||
),
|
||||
).toList();
|
||||
|
@ -8,6 +8,11 @@ import 'package:immich_mobile/domain/models/log.model.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
/// Service responsible for handling application logging.
|
||||
///
|
||||
/// It listens to Dart's [Logger.root], buffers logs in memory (optionally),
|
||||
/// writes them to a persistent [ILogRepository], and manages log levels
|
||||
/// via [IStoreRepository]
|
||||
class LogService {
|
||||
final ILogRepository _logRepository;
|
||||
final IStoreRepository _storeRepository;
|
||||
@ -18,19 +23,11 @@ class LogService {
|
||||
/// This is useful when logging in quick succession, as it increases performance
|
||||
/// and reduces NAND wear. However, it may cause the logs to be lost in case of a crash / in isolates.
|
||||
final bool _shouldBuffer;
|
||||
|
||||
Timer? _flushTimer;
|
||||
|
||||
late final StreamSubscription<LogRecord> _logSubscription;
|
||||
|
||||
LogService._(
|
||||
this._logRepository,
|
||||
this._storeRepository,
|
||||
this._shouldBuffer,
|
||||
) {
|
||||
// Listen to log messages and write them to the database
|
||||
_logSubscription = Logger.root.onRecord.listen(_writeLogToDatabase);
|
||||
}
|
||||
|
||||
static LogService? _instance;
|
||||
static LogService get I {
|
||||
if (_instance == null) {
|
||||
@ -44,10 +41,7 @@ class LogService {
|
||||
required IStoreRepository storeRepository,
|
||||
bool shouldBuffer = true,
|
||||
}) async {
|
||||
if (_instance != null) {
|
||||
return _instance!;
|
||||
}
|
||||
_instance = await create(
|
||||
_instance ??= await create(
|
||||
logRepository: logRepository,
|
||||
storeRepository: storeRepository,
|
||||
shouldBuffer: shouldBuffer,
|
||||
@ -61,55 +55,28 @@ class LogService {
|
||||
bool shouldBuffer = true,
|
||||
}) async {
|
||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
||||
// Truncate logs to 250
|
||||
await logRepository.truncate(limit: kLogTruncateLimit);
|
||||
// Get log level from store
|
||||
final level = await instance._storeRepository.tryGet(StoreKey.logLevel);
|
||||
if (level != null) {
|
||||
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
|
||||
}
|
||||
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ??
|
||||
LogLevel.info.index;
|
||||
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Future<void> setlogLevel(LogLevel level) async {
|
||||
await _storeRepository.insert(StoreKey.logLevel, level.index);
|
||||
Logger.root.level = level.toLevel();
|
||||
LogService._(
|
||||
this._logRepository,
|
||||
this._storeRepository,
|
||||
this._shouldBuffer,
|
||||
) {
|
||||
_logSubscription = Logger.root.onRecord.listen(_handleLogRecord);
|
||||
}
|
||||
|
||||
Future<List<LogMessage>> getMessages() async {
|
||||
final logsFromDb = await _logRepository.getAll();
|
||||
if (_msgBuffer.isNotEmpty) {
|
||||
return [..._msgBuffer.reversed, ...logsFromDb];
|
||||
}
|
||||
return logsFromDb;
|
||||
}
|
||||
|
||||
Future<void> clearLogs() async {
|
||||
_flushTimer?.cancel();
|
||||
_flushTimer = null;
|
||||
_msgBuffer.clear();
|
||||
await _logRepository.deleteAll();
|
||||
}
|
||||
|
||||
/// Flush pending log messages to persistent storage
|
||||
void flush() {
|
||||
if (_flushTimer == null) {
|
||||
return;
|
||||
}
|
||||
_flushTimer!.cancel();
|
||||
// TODO: Rename enable this after moving to sqlite - #16504
|
||||
// await _flushBufferToDatabase();
|
||||
}
|
||||
|
||||
Future<void> dispose() {
|
||||
_flushTimer?.cancel();
|
||||
_logSubscription.cancel();
|
||||
return _flushBufferToDatabase();
|
||||
}
|
||||
|
||||
void _writeLogToDatabase(LogRecord r) {
|
||||
void _handleLogRecord(LogRecord r) {
|
||||
if (kDebugMode) {
|
||||
debugPrint('[${r.level.name}] [${r.time}] ${r.message}');
|
||||
debugPrint(
|
||||
'[${r.level.name}] [${r.time}] [${r.loggerName}] ${r.message}'
|
||||
'${r.error == null ? '' : '\nError: ${r.error}'}'
|
||||
'${r.stackTrace == null ? '' : '\nStack: ${r.stackTrace}'}',
|
||||
);
|
||||
}
|
||||
|
||||
final record = LogMessage(
|
||||
@ -125,14 +92,44 @@ class LogService {
|
||||
_msgBuffer.add(record);
|
||||
_flushTimer ??= Timer(
|
||||
const Duration(seconds: 5),
|
||||
() => unawaited(_flushBufferToDatabase()),
|
||||
() => unawaited(flushBuffer()),
|
||||
);
|
||||
} else {
|
||||
unawaited(_logRepository.insert(record));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _flushBufferToDatabase() async {
|
||||
Future<void> setLogLevel(LogLevel level) async {
|
||||
await _storeRepository.insert(StoreKey.logLevel, level.index);
|
||||
Logger.root.level = level.toLevel();
|
||||
}
|
||||
|
||||
Future<List<LogMessage>> getMessages() async {
|
||||
final logsFromDb = await _logRepository.getAll();
|
||||
return [..._msgBuffer.reversed, ...logsFromDb];
|
||||
}
|
||||
|
||||
Future<void> clearLogs() async {
|
||||
_flushTimer?.cancel();
|
||||
_flushTimer = null;
|
||||
_msgBuffer.clear();
|
||||
await _logRepository.deleteAll();
|
||||
}
|
||||
|
||||
void flush() {
|
||||
_flushTimer?.cancel();
|
||||
// TODO: Rename enable this after moving to sqlite - #16504
|
||||
// await _flushBufferToDatabase();
|
||||
}
|
||||
|
||||
Future<void> dispose() {
|
||||
_flushTimer?.cancel();
|
||||
_logSubscription.cancel();
|
||||
return flushBuffer();
|
||||
}
|
||||
|
||||
// TOOD: Move this to private once Isar is removed
|
||||
Future<void> flushBuffer() async {
|
||||
_flushTimer = null;
|
||||
final buffer = [..._msgBuffer];
|
||||
_msgBuffer.clear();
|
||||
|
@ -3,15 +3,17 @@ import 'dart:async';
|
||||
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
|
||||
/// Provides access to a persistent key-value store with an in-memory cache.
|
||||
/// Listens for repository changes to keep the cache updated.
|
||||
class StoreService {
|
||||
final IStoreRepository _storeRepository;
|
||||
|
||||
final Map<int, dynamic> _cache = {};
|
||||
late final StreamSubscription<StoreUpdateEvent> _storeUpdateSubscription;
|
||||
/// In-memory cache. Keys are [StoreKey.id]
|
||||
final Map<int, Object?> _cache = {};
|
||||
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
||||
|
||||
StoreService._({
|
||||
required IStoreRepository storeRepository,
|
||||
}) : _storeRepository = storeRepository;
|
||||
StoreService._({required IStoreRepository storeRepository})
|
||||
: _storeRepository = storeRepository;
|
||||
|
||||
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
||||
static StoreService? _instance;
|
||||
@ -23,7 +25,6 @@ class StoreService {
|
||||
}
|
||||
|
||||
// TODO: Replace the implementation with the one from create after removing the typedef
|
||||
/// Initializes the store with the given [storeRepository]
|
||||
static Future<StoreService> init({
|
||||
required IStoreRepository storeRepository,
|
||||
}) async {
|
||||
@ -31,7 +32,6 @@ class StoreService {
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
/// Initializes the store with the given [storeRepository]
|
||||
static Future<StoreService> create({
|
||||
required IStoreRepository storeRepository,
|
||||
}) async {
|
||||
@ -41,16 +41,14 @@ class StoreService {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Fills the cache with the values from the DB
|
||||
Future<void> _populateCache() async {
|
||||
for (StoreKey key in StoreKey.values) {
|
||||
final storeValue = await _storeRepository.tryGet(key);
|
||||
_cache[key.id] = storeValue;
|
||||
final storeValues = await _storeRepository.getAll();
|
||||
for (StoreDto storeValue in storeValues) {
|
||||
_cache[storeValue.key.id] = storeValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Listens for changes in the DB and updates the cache
|
||||
StreamSubscription<StoreUpdateEvent> _listenForChange() =>
|
||||
StreamSubscription<StoreDto> _listenForChange() =>
|
||||
_storeRepository.watchAll().listen((event) {
|
||||
_cache[event.key.id] = event.value;
|
||||
});
|
||||
@ -61,11 +59,11 @@ class StoreService {
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
/// Returns the stored value for the given key (possibly null)
|
||||
T? tryGet<T>(StoreKey<T> key) => _cache[key.id];
|
||||
/// Returns the cached value for [key], or `null`
|
||||
T? tryGet<T>(StoreKey<T> key) => _cache[key.id] as T?;
|
||||
|
||||
/// Returns the stored value for the given key or if null the [defaultValue]
|
||||
/// Throws a [StoreKeyNotFoundException] if both are null
|
||||
/// Returns the stored value for [key] or [defaultValue].
|
||||
/// Throws [StoreKeyNotFoundException] if value and [defaultValue] are null.
|
||||
T get<T>(StoreKey<T> key, [T? defaultValue]) {
|
||||
final value = tryGet(key) ?? defaultValue;
|
||||
if (value == null) {
|
||||
@ -74,23 +72,23 @@ class StoreService {
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Asynchronously stores the value in the Store
|
||||
/// Stores the [value] for the [key]. Skips write if value hasn't changed.
|
||||
Future<void> put<U extends StoreKey<T>, T>(U key, T value) async {
|
||||
if (_cache[key.id] == value) return;
|
||||
await _storeRepository.insert(key, value);
|
||||
_cache[key.id] = value;
|
||||
}
|
||||
|
||||
/// Watches a specific key for changes
|
||||
/// Returns a stream that emits the value for [key] on change.
|
||||
Stream<T?> watch<T>(StoreKey<T> key) => _storeRepository.watch(key);
|
||||
|
||||
/// Removes the value asynchronously from the Store
|
||||
/// Removes the value for [key]
|
||||
Future<void> delete<T>(StoreKey<T> key) async {
|
||||
await _storeRepository.delete(key);
|
||||
_cache.remove(key.id);
|
||||
}
|
||||
|
||||
/// Clears all values from this store (cache and DB)
|
||||
/// Clears all values from thw store (cache and DB)
|
||||
Future<void> clear() async {
|
||||
await _storeRepository.deleteAll();
|
||||
_cache.clear();
|
||||
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: avoid-passing-async-when-sync-expected
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||
@ -59,8 +57,7 @@ class SyncStreamService {
|
||||
|
||||
Future<void> _handleSyncData(
|
||||
SyncEntityType type,
|
||||
// ignore: avoid-dynamic
|
||||
Iterable<dynamic> data,
|
||||
Iterable<Object> data,
|
||||
) async {
|
||||
_logger.fine("Processing sync data for $type of length ${data.length}");
|
||||
switch (type) {
|
||||
@ -84,6 +81,18 @@ class SyncStreamService {
|
||||
return _syncStreamRepository.deletePartnerAssetsV1(data.cast());
|
||||
case SyncEntityType.partnerAssetExifV1:
|
||||
return _syncStreamRepository.updatePartnerAssetsExifV1(data.cast());
|
||||
case SyncEntityType.albumV1:
|
||||
return _syncStreamRepository.updateAlbumsV1(data.cast());
|
||||
case SyncEntityType.albumDeleteV1:
|
||||
return _syncStreamRepository.deleteAlbumsV1(data.cast());
|
||||
// case SyncEntityType.albumAssetV1:
|
||||
// return _syncStreamRepository.updateAlbumAssetsV1(data.cast());
|
||||
// case SyncEntityType.albumAssetDeleteV1:
|
||||
// return _syncStreamRepository.deleteAlbumAssetsV1(data.cast());
|
||||
case SyncEntityType.albumUserV1:
|
||||
return _syncStreamRepository.updateAlbumUsersV1(data.cast());
|
||||
case SyncEntityType.albumUserDeleteV1:
|
||||
return _syncStreamRepository.deleteAlbumUsersV1(data.cast());
|
||||
default:
|
||||
_logger.warning("Unknown sync data type: $type");
|
||||
}
|
||||
|
20
mobile/lib/infrastructure/entities/album_user.entity.dart
Normal file
20
mobile/lib/infrastructure/entities/album_user.entity.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album_user.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||
|
||||
class AlbumUserEntity extends Table with DriftDefaultsMixin {
|
||||
const AlbumUserEntity();
|
||||
|
||||
TextColumn get albumId =>
|
||||
text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
|
||||
|
||||
TextColumn get userId =>
|
||||
text().references(UserEntity, #id, onDelete: KeyAction.cascade)();
|
||||
|
||||
IntColumn get role => intEnum<AlbumUserRole>()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {albumId, userId};
|
||||
}
|
602
mobile/lib/infrastructure/entities/album_user.entity.drift.dart
generated
Normal file
602
mobile/lib/infrastructure/entities/album_user.entity.drift.dart
generated
Normal file
@ -0,0 +1,602 @@
|
||||
// dart format width=80
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:immich_mobile/infrastructure/entities/album_user.entity.drift.dart'
|
||||
as i1;
|
||||
import 'package:immich_mobile/domain/models/album_user.model.dart' as i2;
|
||||
import 'package:immich_mobile/infrastructure/entities/album_user.entity.dart'
|
||||
as i3;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||
as i4;
|
||||
import 'package:drift/internal/modular.dart' as i5;
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart'
|
||||
as i6;
|
||||
|
||||
typedef $$AlbumUserEntityTableCreateCompanionBuilder
|
||||
= i1.AlbumUserEntityCompanion Function({
|
||||
required String albumId,
|
||||
required String userId,
|
||||
required i2.AlbumUserRole role,
|
||||
});
|
||||
typedef $$AlbumUserEntityTableUpdateCompanionBuilder
|
||||
= i1.AlbumUserEntityCompanion Function({
|
||||
i0.Value<String> albumId,
|
||||
i0.Value<String> userId,
|
||||
i0.Value<i2.AlbumUserRole> role,
|
||||
});
|
||||
|
||||
final class $$AlbumUserEntityTableReferences extends i0.BaseReferences<
|
||||
i0.GeneratedDatabase, i1.$AlbumUserEntityTable, i1.AlbumUserEntityData> {
|
||||
$$AlbumUserEntityTableReferences(
|
||||
super.$_db, super.$_table, super.$_typedResult);
|
||||
|
||||
static i4.$RemoteAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AlbumUserEntityTable>('album_user_entity')
|
||||
.albumId,
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.id));
|
||||
|
||||
i4.$$RemoteAlbumEntityTableProcessedTableManager get albumId {
|
||||
final $_column = $_itemColumn<String>('album_id')!;
|
||||
|
||||
final manager = i4
|
||||
.$$RemoteAlbumEntityTableTableManager(
|
||||
$_db,
|
||||
i5.ReadDatabaseContainer($_db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_albumIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
|
||||
static i6.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AlbumUserEntityTable>('album_user_entity')
|
||||
.userId,
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity')
|
||||
.id));
|
||||
|
||||
i6.$$UserEntityTableProcessedTableManager get userId {
|
||||
final $_column = $_itemColumn<String>('user_id')!;
|
||||
|
||||
final manager = i6
|
||||
.$$UserEntityTableTableManager(
|
||||
$_db,
|
||||
i5.ReadDatabaseContainer($_db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_userIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
}
|
||||
|
||||
class $$AlbumUserEntityTableFilterComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AlbumUserEntityTable> {
|
||||
$$AlbumUserEntityTableFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnWithTypeConverterFilters<i2.AlbumUserRole, i2.AlbumUserRole, int>
|
||||
get role => $composableBuilder(
|
||||
column: $table.role,
|
||||
builder: (column) => i0.ColumnWithTypeConverterFilters(column));
|
||||
|
||||
i4.$$RemoteAlbumEntityTableFilterComposer get albumId {
|
||||
final i4.$$RemoteAlbumEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$RemoteAlbumEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i6.$$UserEntityTableFilterComposer get userId {
|
||||
final i6.$$UserEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i6.$$UserEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AlbumUserEntityTableOrderingComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AlbumUserEntityTable> {
|
||||
$$AlbumUserEntityTableOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnOrderings<int> get role => $composableBuilder(
|
||||
column: $table.role, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i4.$$RemoteAlbumEntityTableOrderingComposer get albumId {
|
||||
final i4.$$RemoteAlbumEntityTableOrderingComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$RemoteAlbumEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>(
|
||||
'remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i6.$$UserEntityTableOrderingComposer get userId {
|
||||
final i6.$$UserEntityTableOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i6.$$UserEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AlbumUserEntityTableAnnotationComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$AlbumUserEntityTable> {
|
||||
$$AlbumUserEntityTableAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.GeneratedColumnWithTypeConverter<i2.AlbumUserRole, int> get role =>
|
||||
$composableBuilder(column: $table.role, builder: (column) => column);
|
||||
|
||||
i4.$$RemoteAlbumEntityTableAnnotationComposer get albumId {
|
||||
final i4.$$RemoteAlbumEntityTableAnnotationComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i4.$$RemoteAlbumEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>(
|
||||
'remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i6.$$UserEntityTableAnnotationComposer get userId {
|
||||
final i6.$$UserEntityTableAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.userId,
|
||||
referencedTable: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i6.$$UserEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i5.ReadDatabaseContainer($db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$AlbumUserEntityTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$AlbumUserEntityTable,
|
||||
i1.AlbumUserEntityData,
|
||||
i1.$$AlbumUserEntityTableFilterComposer,
|
||||
i1.$$AlbumUserEntityTableOrderingComposer,
|
||||
i1.$$AlbumUserEntityTableAnnotationComposer,
|
||||
$$AlbumUserEntityTableCreateCompanionBuilder,
|
||||
$$AlbumUserEntityTableUpdateCompanionBuilder,
|
||||
(i1.AlbumUserEntityData, i1.$$AlbumUserEntityTableReferences),
|
||||
i1.AlbumUserEntityData,
|
||||
i0.PrefetchHooks Function({bool albumId, bool userId})> {
|
||||
$$AlbumUserEntityTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$AlbumUserEntityTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
i1.$$AlbumUserEntityTableFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
i1.$$AlbumUserEntityTableOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () => i1
|
||||
.$$AlbumUserEntityTableAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
i0.Value<String> albumId = const i0.Value.absent(),
|
||||
i0.Value<String> userId = const i0.Value.absent(),
|
||||
i0.Value<i2.AlbumUserRole> role = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.AlbumUserEntityCompanion(
|
||||
albumId: albumId,
|
||||
userId: userId,
|
||||
role: role,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String albumId,
|
||||
required String userId,
|
||||
required i2.AlbumUserRole role,
|
||||
}) =>
|
||||
i1.AlbumUserEntityCompanion.insert(
|
||||
albumId: albumId,
|
||||
userId: userId,
|
||||
role: role,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) => (
|
||||
e.readTable(table),
|
||||
i1.$$AlbumUserEntityTableReferences(db, table, e)
|
||||
))
|
||||
.toList(),
|
||||
prefetchHooksCallback: ({albumId = false, userId = false}) {
|
||||
return i0.PrefetchHooks(
|
||||
db: db,
|
||||
explicitlyWatchedTables: [],
|
||||
addJoins: <
|
||||
T extends i0.TableManagerState<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic>>(state) {
|
||||
if (albumId) {
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.albumId,
|
||||
referencedTable:
|
||||
i1.$$AlbumUserEntityTableReferences._albumIdTable(db),
|
||||
referencedColumn: i1.$$AlbumUserEntityTableReferences
|
||||
._albumIdTable(db)
|
||||
.id,
|
||||
) as T;
|
||||
}
|
||||
if (userId) {
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.userId,
|
||||
referencedTable:
|
||||
i1.$$AlbumUserEntityTableReferences._userIdTable(db),
|
||||
referencedColumn:
|
||||
i1.$$AlbumUserEntityTableReferences._userIdTable(db).id,
|
||||
) as T;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
getPrefetchedDataCallback: (items) async {
|
||||
return [];
|
||||
},
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
typedef $$AlbumUserEntityTableProcessedTableManager = i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$AlbumUserEntityTable,
|
||||
i1.AlbumUserEntityData,
|
||||
i1.$$AlbumUserEntityTableFilterComposer,
|
||||
i1.$$AlbumUserEntityTableOrderingComposer,
|
||||
i1.$$AlbumUserEntityTableAnnotationComposer,
|
||||
$$AlbumUserEntityTableCreateCompanionBuilder,
|
||||
$$AlbumUserEntityTableUpdateCompanionBuilder,
|
||||
(i1.AlbumUserEntityData, i1.$$AlbumUserEntityTableReferences),
|
||||
i1.AlbumUserEntityData,
|
||||
i0.PrefetchHooks Function({bool albumId, bool userId})>;
|
||||
|
||||
class $AlbumUserEntityTable extends i3.AlbumUserEntity
|
||||
with i0.TableInfo<$AlbumUserEntityTable, i1.AlbumUserEntityData> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$AlbumUserEntityTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _albumIdMeta =
|
||||
const i0.VerificationMeta('albumId');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> albumId = i0.GeneratedColumn<String>(
|
||||
'album_id', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES remote_album_entity (id) ON DELETE CASCADE'));
|
||||
static const i0.VerificationMeta _userIdMeta =
|
||||
const i0.VerificationMeta('userId');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> userId = i0.GeneratedColumn<String>(
|
||||
'user_id', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES user_entity (id) ON DELETE CASCADE'));
|
||||
@override
|
||||
late final i0.GeneratedColumnWithTypeConverter<i2.AlbumUserRole, int> role =
|
||||
i0.GeneratedColumn<int>('role', aliasedName, false,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: true)
|
||||
.withConverter<i2.AlbumUserRole>(
|
||||
i1.$AlbumUserEntityTable.$converterrole);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [albumId, userId, role];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'album_user_entity';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.AlbumUserEntityData> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = i0.VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('album_id')) {
|
||||
context.handle(_albumIdMeta,
|
||||
albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_albumIdMeta);
|
||||
}
|
||||
if (data.containsKey('user_id')) {
|
||||
context.handle(_userIdMeta,
|
||||
userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_userIdMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {albumId, userId};
|
||||
@override
|
||||
i1.AlbumUserEntityData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.AlbumUserEntityData(
|
||||
albumId: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!,
|
||||
userId: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}user_id'])!,
|
||||
role: i1.$AlbumUserEntityTable.$converterrole.fromSql(attachedDatabase
|
||||
.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}role'])!),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$AlbumUserEntityTable createAlias(String alias) {
|
||||
return $AlbumUserEntityTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static i0.JsonTypeConverter2<i2.AlbumUserRole, int, int> $converterrole =
|
||||
const i0.EnumIndexConverter<i2.AlbumUserRole>(i2.AlbumUserRole.values);
|
||||
@override
|
||||
bool get withoutRowId => true;
|
||||
@override
|
||||
bool get isStrict => true;
|
||||
}
|
||||
|
||||
class AlbumUserEntityData extends i0.DataClass
|
||||
implements i0.Insertable<i1.AlbumUserEntityData> {
|
||||
final String albumId;
|
||||
final String userId;
|
||||
final i2.AlbumUserRole role;
|
||||
const AlbumUserEntityData(
|
||||
{required this.albumId, required this.userId, required this.role});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['album_id'] = i0.Variable<String>(albumId);
|
||||
map['user_id'] = i0.Variable<String>(userId);
|
||||
{
|
||||
map['role'] =
|
||||
i0.Variable<int>(i1.$AlbumUserEntityTable.$converterrole.toSql(role));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
factory AlbumUserEntityData.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return AlbumUserEntityData(
|
||||
albumId: serializer.fromJson<String>(json['albumId']),
|
||||
userId: serializer.fromJson<String>(json['userId']),
|
||||
role: i1.$AlbumUserEntityTable.$converterrole
|
||||
.fromJson(serializer.fromJson<int>(json['role'])),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'albumId': serializer.toJson<String>(albumId),
|
||||
'userId': serializer.toJson<String>(userId),
|
||||
'role': serializer
|
||||
.toJson<int>(i1.$AlbumUserEntityTable.$converterrole.toJson(role)),
|
||||
};
|
||||
}
|
||||
|
||||
i1.AlbumUserEntityData copyWith(
|
||||
{String? albumId, String? userId, i2.AlbumUserRole? role}) =>
|
||||
i1.AlbumUserEntityData(
|
||||
albumId: albumId ?? this.albumId,
|
||||
userId: userId ?? this.userId,
|
||||
role: role ?? this.role,
|
||||
);
|
||||
AlbumUserEntityData copyWithCompanion(i1.AlbumUserEntityCompanion data) {
|
||||
return AlbumUserEntityData(
|
||||
albumId: data.albumId.present ? data.albumId.value : this.albumId,
|
||||
userId: data.userId.present ? data.userId.value : this.userId,
|
||||
role: data.role.present ? data.role.value : this.role,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('AlbumUserEntityData(')
|
||||
..write('albumId: $albumId, ')
|
||||
..write('userId: $userId, ')
|
||||
..write('role: $role')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(albumId, userId, role);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.AlbumUserEntityData &&
|
||||
other.albumId == this.albumId &&
|
||||
other.userId == this.userId &&
|
||||
other.role == this.role);
|
||||
}
|
||||
|
||||
class AlbumUserEntityCompanion
|
||||
extends i0.UpdateCompanion<i1.AlbumUserEntityData> {
|
||||
final i0.Value<String> albumId;
|
||||
final i0.Value<String> userId;
|
||||
final i0.Value<i2.AlbumUserRole> role;
|
||||
const AlbumUserEntityCompanion({
|
||||
this.albumId = const i0.Value.absent(),
|
||||
this.userId = const i0.Value.absent(),
|
||||
this.role = const i0.Value.absent(),
|
||||
});
|
||||
AlbumUserEntityCompanion.insert({
|
||||
required String albumId,
|
||||
required String userId,
|
||||
required i2.AlbumUserRole role,
|
||||
}) : albumId = i0.Value(albumId),
|
||||
userId = i0.Value(userId),
|
||||
role = i0.Value(role);
|
||||
static i0.Insertable<i1.AlbumUserEntityData> custom({
|
||||
i0.Expression<String>? albumId,
|
||||
i0.Expression<String>? userId,
|
||||
i0.Expression<int>? role,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (albumId != null) 'album_id': albumId,
|
||||
if (userId != null) 'user_id': userId,
|
||||
if (role != null) 'role': role,
|
||||
});
|
||||
}
|
||||
|
||||
i1.AlbumUserEntityCompanion copyWith(
|
||||
{i0.Value<String>? albumId,
|
||||
i0.Value<String>? userId,
|
||||
i0.Value<i2.AlbumUserRole>? role}) {
|
||||
return i1.AlbumUserEntityCompanion(
|
||||
albumId: albumId ?? this.albumId,
|
||||
userId: userId ?? this.userId,
|
||||
role: role ?? this.role,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (albumId.present) {
|
||||
map['album_id'] = i0.Variable<String>(albumId.value);
|
||||
}
|
||||
if (userId.present) {
|
||||
map['user_id'] = i0.Variable<String>(userId.value);
|
||||
}
|
||||
if (role.present) {
|
||||
map['role'] = i0.Variable<int>(
|
||||
i1.$AlbumUserEntityTable.$converterrole.toSql(role.value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('AlbumUserEntityCompanion(')
|
||||
..write('albumId: $albumId, ')
|
||||
..write('userId: $userId, ')
|
||||
..write('role: $role')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ typedef $$LocalAssetEntityTableCreateCompanionBuilder
|
||||
required i2.AssetType type,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
i0.Value<int?> width,
|
||||
i0.Value<int?> height,
|
||||
i0.Value<int?> durationInSeconds,
|
||||
required String id,
|
||||
i0.Value<String?> checksum,
|
||||
@ -25,6 +27,8 @@ typedef $$LocalAssetEntityTableUpdateCompanionBuilder
|
||||
i0.Value<i2.AssetType> type,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
i0.Value<int?> width,
|
||||
i0.Value<int?> height,
|
||||
i0.Value<int?> durationInSeconds,
|
||||
i0.Value<String> id,
|
||||
i0.Value<String?> checksum,
|
||||
@ -54,6 +58,12 @@ class $$LocalAssetEntityTableFilterComposer
|
||||
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get width => $composableBuilder(
|
||||
column: $table.width, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get height => $composableBuilder(
|
||||
column: $table.height, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds,
|
||||
builder: (column) => i0.ColumnFilters(column));
|
||||
@ -91,6 +101,12 @@ class $$LocalAssetEntityTableOrderingComposer
|
||||
column: $table.updatedAt,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get width => $composableBuilder(
|
||||
column: $table.width, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get height => $composableBuilder(
|
||||
column: $table.height, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
@ -127,6 +143,12 @@ class $$LocalAssetEntityTableAnnotationComposer
|
||||
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get width =>
|
||||
$composableBuilder(column: $table.width, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get height =>
|
||||
$composableBuilder(column: $table.height, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds, builder: (column) => column);
|
||||
|
||||
@ -173,6 +195,8 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
i0.Value<i2.AssetType> type = const i0.Value.absent(),
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
i0.Value<String> id = const i0.Value.absent(),
|
||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||
@ -183,6 +207,8 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
type: type,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds,
|
||||
id: id,
|
||||
checksum: checksum,
|
||||
@ -193,6 +219,8 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
required i2.AssetType type,
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
required String id,
|
||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||
@ -203,6 +231,8 @@ class $$LocalAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
type: type,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds,
|
||||
id: id,
|
||||
checksum: checksum,
|
||||
@ -268,6 +298,18 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
||||
type: i0.DriftSqlType.dateTime,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: i4.currentDateAndTime);
|
||||
static const i0.VerificationMeta _widthMeta =
|
||||
const i0.VerificationMeta('width');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> width = i0.GeneratedColumn<int>(
|
||||
'width', aliasedName, true,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||
static const i0.VerificationMeta _heightMeta =
|
||||
const i0.VerificationMeta('height');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> height = i0.GeneratedColumn<int>(
|
||||
'height', aliasedName, true,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||
static const i0.VerificationMeta _durationInSecondsMeta =
|
||||
const i0.VerificationMeta('durationInSeconds');
|
||||
@override
|
||||
@ -301,6 +343,8 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
id,
|
||||
checksum,
|
||||
@ -331,6 +375,14 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
||||
context.handle(_updatedAtMeta,
|
||||
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
|
||||
}
|
||||
if (data.containsKey('width')) {
|
||||
context.handle(
|
||||
_widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta));
|
||||
}
|
||||
if (data.containsKey('height')) {
|
||||
context.handle(_heightMeta,
|
||||
height.isAcceptableOrUnknown(data['height']!, _heightMeta));
|
||||
}
|
||||
if (data.containsKey('duration_in_seconds')) {
|
||||
context.handle(
|
||||
_durationInSecondsMeta,
|
||||
@ -371,6 +423,10 @@ class $LocalAssetEntityTable extends i3.LocalAssetEntity
|
||||
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
|
||||
updatedAt: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
|
||||
width: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}width']),
|
||||
height: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}height']),
|
||||
durationInSeconds: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
||||
id: attachedDatabase.typeMapping
|
||||
@ -401,6 +457,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
final i2.AssetType type;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final int? width;
|
||||
final int? height;
|
||||
final int? durationInSeconds;
|
||||
final String id;
|
||||
final String? checksum;
|
||||
@ -410,6 +468,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
required this.type,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.width,
|
||||
this.height,
|
||||
this.durationInSeconds,
|
||||
required this.id,
|
||||
this.checksum,
|
||||
@ -424,6 +484,12 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
}
|
||||
map['created_at'] = i0.Variable<DateTime>(createdAt);
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||
if (!nullToAbsent || width != null) {
|
||||
map['width'] = i0.Variable<int>(width);
|
||||
}
|
||||
if (!nullToAbsent || height != null) {
|
||||
map['height'] = i0.Variable<int>(height);
|
||||
}
|
||||
if (!nullToAbsent || durationInSeconds != null) {
|
||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
||||
}
|
||||
@ -444,6 +510,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
.fromJson(serializer.fromJson<int>(json['type'])),
|
||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||
width: serializer.fromJson<int?>(json['width']),
|
||||
height: serializer.fromJson<int?>(json['height']),
|
||||
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
checksum: serializer.fromJson<String?>(json['checksum']),
|
||||
@ -459,6 +527,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
.toJson<int>(i1.$LocalAssetEntityTable.$convertertype.toJson(type)),
|
||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||
'width': serializer.toJson<int?>(width),
|
||||
'height': serializer.toJson<int?>(height),
|
||||
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
||||
'id': serializer.toJson<String>(id),
|
||||
'checksum': serializer.toJson<String?>(checksum),
|
||||
@ -471,6 +541,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
i2.AssetType? type,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
String? id,
|
||||
i0.Value<String?> checksum = const i0.Value.absent(),
|
||||
@ -480,6 +552,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
type: type ?? this.type,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
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,
|
||||
@ -493,6 +567,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
type: data.type.present ? data.type.value : this.type,
|
||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||
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,
|
||||
@ -510,6 +586,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
..write('type: $type, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('width: $width, ')
|
||||
..write('height: $height, ')
|
||||
..write('durationInSeconds: $durationInSeconds, ')
|
||||
..write('id: $id, ')
|
||||
..write('checksum: $checksum, ')
|
||||
@ -519,8 +597,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(name, type, createdAt, updatedAt,
|
||||
durationInSeconds, id, checksum, isFavorite);
|
||||
int get hashCode => Object.hash(name, type, createdAt, updatedAt, width,
|
||||
height, durationInSeconds, id, checksum, isFavorite);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
@ -529,6 +607,8 @@ class LocalAssetEntityData extends i0.DataClass
|
||||
other.type == this.type &&
|
||||
other.createdAt == this.createdAt &&
|
||||
other.updatedAt == this.updatedAt &&
|
||||
other.width == this.width &&
|
||||
other.height == this.height &&
|
||||
other.durationInSeconds == this.durationInSeconds &&
|
||||
other.id == this.id &&
|
||||
other.checksum == this.checksum &&
|
||||
@ -541,6 +621,8 @@ class LocalAssetEntityCompanion
|
||||
final i0.Value<i2.AssetType> type;
|
||||
final i0.Value<DateTime> createdAt;
|
||||
final i0.Value<DateTime> updatedAt;
|
||||
final i0.Value<int?> width;
|
||||
final i0.Value<int?> height;
|
||||
final i0.Value<int?> durationInSeconds;
|
||||
final i0.Value<String> id;
|
||||
final i0.Value<String?> checksum;
|
||||
@ -550,6 +632,8 @@ class LocalAssetEntityCompanion
|
||||
this.type = const i0.Value.absent(),
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
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.id = const i0.Value.absent(),
|
||||
this.checksum = const i0.Value.absent(),
|
||||
@ -560,6 +644,8 @@ class LocalAssetEntityCompanion
|
||||
required i2.AssetType type,
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
this.updatedAt = const i0.Value.absent(),
|
||||
this.width = const i0.Value.absent(),
|
||||
this.height = const i0.Value.absent(),
|
||||
this.durationInSeconds = const i0.Value.absent(),
|
||||
required String id,
|
||||
this.checksum = const i0.Value.absent(),
|
||||
@ -572,6 +658,8 @@ class LocalAssetEntityCompanion
|
||||
i0.Expression<int>? type,
|
||||
i0.Expression<DateTime>? createdAt,
|
||||
i0.Expression<DateTime>? updatedAt,
|
||||
i0.Expression<int>? width,
|
||||
i0.Expression<int>? height,
|
||||
i0.Expression<int>? durationInSeconds,
|
||||
i0.Expression<String>? id,
|
||||
i0.Expression<String>? checksum,
|
||||
@ -582,6 +670,8 @@ class LocalAssetEntityCompanion
|
||||
if (type != null) 'type': type,
|
||||
if (createdAt != null) 'created_at': createdAt,
|
||||
if (updatedAt != null) 'updated_at': updatedAt,
|
||||
if (width != null) 'width': width,
|
||||
if (height != null) 'height': height,
|
||||
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
||||
if (id != null) 'id': id,
|
||||
if (checksum != null) 'checksum': checksum,
|
||||
@ -594,6 +684,8 @@ class LocalAssetEntityCompanion
|
||||
i0.Value<i2.AssetType>? type,
|
||||
i0.Value<DateTime>? createdAt,
|
||||
i0.Value<DateTime>? updatedAt,
|
||||
i0.Value<int?>? width,
|
||||
i0.Value<int?>? height,
|
||||
i0.Value<int?>? durationInSeconds,
|
||||
i0.Value<String>? id,
|
||||
i0.Value<String?>? checksum,
|
||||
@ -603,6 +695,8 @@ class LocalAssetEntityCompanion
|
||||
type: type ?? this.type,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
width: width ?? this.width,
|
||||
height: height ?? this.height,
|
||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||
id: id ?? this.id,
|
||||
checksum: checksum ?? this.checksum,
|
||||
@ -626,6 +720,12 @@ class LocalAssetEntityCompanion
|
||||
if (updatedAt.present) {
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||
}
|
||||
if (width.present) {
|
||||
map['width'] = i0.Variable<int>(width.value);
|
||||
}
|
||||
if (height.present) {
|
||||
map['height'] = i0.Variable<int>(height.value);
|
||||
}
|
||||
if (durationInSeconds.present) {
|
||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds.value);
|
||||
}
|
||||
@ -648,6 +748,8 @@ class LocalAssetEntityCompanion
|
||||
..write('type: $type, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('width: $width, ')
|
||||
..write('height: $height, ')
|
||||
..write('durationInSeconds: $durationInSeconds, ')
|
||||
..write('id: $id, ')
|
||||
..write('checksum: $checksum, ')
|
||||
|
34
mobile/lib/infrastructure/entities/remote_album.entity.dart
Normal file
34
mobile/lib/infrastructure/entities/remote_album.entity.dart
Normal file
@ -0,0 +1,34 @@
|
||||
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';
|
||||
|
||||
class RemoteAlbumEntity extends Table with DriftDefaultsMixin {
|
||||
const RemoteAlbumEntity();
|
||||
|
||||
TextColumn get id => text()();
|
||||
|
||||
TextColumn get name => text()();
|
||||
|
||||
TextColumn get description => text()();
|
||||
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
|
||||
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()();
|
||||
|
||||
BoolColumn get isActivityEnabled =>
|
||||
boolean().withDefault(const Constant(true))();
|
||||
|
||||
IntColumn get order => intEnum<AssetOrder>()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
}
|
946
mobile/lib/infrastructure/entities/remote_album.entity.drift.dart
generated
Normal file
946
mobile/lib/infrastructure/entities/remote_album.entity.drift.dart
generated
Normal file
@ -0,0 +1,946 @@
|
||||
// dart format width=80
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||
as i1;
|
||||
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'
|
||||
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({
|
||||
required String id,
|
||||
required String name,
|
||||
required String description,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
required String ownerId,
|
||||
i0.Value<String?> thumbnailAssetId,
|
||||
i0.Value<bool> isActivityEnabled,
|
||||
required i2.AssetOrder order,
|
||||
});
|
||||
typedef $$RemoteAlbumEntityTableUpdateCompanionBuilder
|
||||
= i1.RemoteAlbumEntityCompanion Function({
|
||||
i0.Value<String> id,
|
||||
i0.Value<String> name,
|
||||
i0.Value<String> description,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
i0.Value<String> ownerId,
|
||||
i0.Value<String?> thumbnailAssetId,
|
||||
i0.Value<bool> isActivityEnabled,
|
||||
i0.Value<i2.AssetOrder> order,
|
||||
});
|
||||
|
||||
final class $$RemoteAlbumEntityTableReferences extends i0.BaseReferences<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumEntityTable,
|
||||
i1.RemoteAlbumEntityData> {
|
||||
$$RemoteAlbumEntityTableReferences(
|
||||
super.$_db, super.$_table, super.$_typedResult);
|
||||
|
||||
static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.ownerId,
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.id));
|
||||
|
||||
i5.$$UserEntityTableProcessedTableManager get ownerId {
|
||||
final $_column = $_itemColumn<String>('owner_id')!;
|
||||
|
||||
final manager = i5
|
||||
.$$UserEntityTableTableManager(
|
||||
$_db,
|
||||
i6.ReadDatabaseContainer($_db)
|
||||
.resultSet<i5.$UserEntityTable>('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(
|
||||
i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.thumbnailAssetId,
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.id));
|
||||
|
||||
i7.$$RemoteAssetEntityTableProcessedTableManager? get thumbnailAssetId {
|
||||
final $_column = $_itemColumn<String>('thumbnail_asset_id');
|
||||
if ($_column == null) return null;
|
||||
final manager = i7
|
||||
.$$RemoteAssetEntityTableTableManager(
|
||||
$_db,
|
||||
i6.ReadDatabaseContainer($_db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_thumbnailAssetIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumEntityTableFilterComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumEntityTable> {
|
||||
$$RemoteAlbumEntityTableFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnFilters<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<String> get name => $composableBuilder(
|
||||
column: $table.name, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<String> get description => $composableBuilder(
|
||||
column: $table.description,
|
||||
builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<DateTime> get createdAt => $composableBuilder(
|
||||
column: $table.createdAt, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<bool> get isActivityEnabled => $composableBuilder(
|
||||
column: $table.isActivityEnabled,
|
||||
builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnWithTypeConverterFilters<i2.AssetOrder, i2.AssetOrder, int>
|
||||
get order => $composableBuilder(
|
||||
column: $table.order,
|
||||
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<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$UserEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i7.$$RemoteAssetEntityTableFilterComposer get thumbnailAssetId {
|
||||
final i7.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.thumbnailAssetId,
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i7.$$RemoteAssetEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumEntityTableOrderingComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumEntityTable> {
|
||||
$$RemoteAlbumEntityTableOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.ColumnOrderings<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<String> get name => $composableBuilder(
|
||||
column: $table.name, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<String> get description => $composableBuilder(
|
||||
column: $table.description,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<DateTime> get createdAt => $composableBuilder(
|
||||
column: $table.createdAt,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<DateTime> get updatedAt => $composableBuilder(
|
||||
column: $table.updatedAt,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<bool> get isActivityEnabled => $composableBuilder(
|
||||
column: $table.isActivityEnabled,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get order => $composableBuilder(
|
||||
column: $table.order, 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<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$UserEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i7.$$RemoteAssetEntityTableOrderingComposer get thumbnailAssetId {
|
||||
final i7.$$RemoteAssetEntityTableOrderingComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.thumbnailAssetId,
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i7.$$RemoteAssetEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>(
|
||||
'remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumEntityTableAnnotationComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumEntityTable> {
|
||||
$$RemoteAlbumEntityTableAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i0.GeneratedColumn<String> get id =>
|
||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<String> get name =>
|
||||
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<String> get description => $composableBuilder(
|
||||
column: $table.description, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<DateTime> get createdAt =>
|
||||
$composableBuilder(column: $table.createdAt, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<bool> get isActivityEnabled => $composableBuilder(
|
||||
column: $table.isActivityEnabled, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumnWithTypeConverter<i2.AssetOrder, int> 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<i5.$UserEntityTable>('user_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$UserEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i7.$$RemoteAssetEntityTableAnnotationComposer get thumbnailAssetId {
|
||||
final i7.$$RemoteAssetEntityTableAnnotationComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.thumbnailAssetId,
|
||||
referencedTable: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i7.$$RemoteAssetEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i6.ReadDatabaseContainer($db)
|
||||
.resultSet<i7.$RemoteAssetEntityTable>(
|
||||
'remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumEntityTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumEntityTable,
|
||||
i1.RemoteAlbumEntityData,
|
||||
i1.$$RemoteAlbumEntityTableFilterComposer,
|
||||
i1.$$RemoteAlbumEntityTableOrderingComposer,
|
||||
i1.$$RemoteAlbumEntityTableAnnotationComposer,
|
||||
$$RemoteAlbumEntityTableCreateCompanionBuilder,
|
||||
$$RemoteAlbumEntityTableUpdateCompanionBuilder,
|
||||
(i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences),
|
||||
i1.RemoteAlbumEntityData,
|
||||
i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})> {
|
||||
$$RemoteAlbumEntityTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$RemoteAlbumEntityTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
i1.$$RemoteAlbumEntityTableFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () => i1
|
||||
.$$RemoteAlbumEntityTableOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
i1.$$RemoteAlbumEntityTableAnnotationComposer(
|
||||
$db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
i0.Value<String> id = const i0.Value.absent(),
|
||||
i0.Value<String> name = const i0.Value.absent(),
|
||||
i0.Value<String> description = const i0.Value.absent(),
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
i0.Value<String> ownerId = const i0.Value.absent(),
|
||||
i0.Value<String?> thumbnailAssetId = const i0.Value.absent(),
|
||||
i0.Value<bool> isActivityEnabled = const i0.Value.absent(),
|
||||
i0.Value<i2.AssetOrder> order = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.RemoteAlbumEntityCompanion(
|
||||
id: id,
|
||||
name: name,
|
||||
description: description,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
ownerId: ownerId,
|
||||
thumbnailAssetId: thumbnailAssetId,
|
||||
isActivityEnabled: isActivityEnabled,
|
||||
order: order,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String id,
|
||||
required String name,
|
||||
required String description,
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
required String ownerId,
|
||||
i0.Value<String?> thumbnailAssetId = const i0.Value.absent(),
|
||||
i0.Value<bool> isActivityEnabled = const i0.Value.absent(),
|
||||
required i2.AssetOrder order,
|
||||
}) =>
|
||||
i1.RemoteAlbumEntityCompanion.insert(
|
||||
id: id,
|
||||
name: name,
|
||||
description: description,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
ownerId: ownerId,
|
||||
thumbnailAssetId: thumbnailAssetId,
|
||||
isActivityEnabled: isActivityEnabled,
|
||||
order: order,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) => (
|
||||
e.readTable(table),
|
||||
i1.$$RemoteAlbumEntityTableReferences(db, table, e)
|
||||
))
|
||||
.toList(),
|
||||
prefetchHooksCallback: ({ownerId = false, thumbnailAssetId = false}) {
|
||||
return i0.PrefetchHooks(
|
||||
db: db,
|
||||
explicitlyWatchedTables: [],
|
||||
addJoins: <
|
||||
T extends i0.TableManagerState<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
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(
|
||||
currentTable: table,
|
||||
currentColumn: table.thumbnailAssetId,
|
||||
referencedTable: i1.$$RemoteAlbumEntityTableReferences
|
||||
._thumbnailAssetIdTable(db),
|
||||
referencedColumn: i1.$$RemoteAlbumEntityTableReferences
|
||||
._thumbnailAssetIdTable(db)
|
||||
.id,
|
||||
) as T;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
getPrefetchedDataCallback: (items) async {
|
||||
return [];
|
||||
},
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
typedef $$RemoteAlbumEntityTableProcessedTableManager
|
||||
= i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumEntityTable,
|
||||
i1.RemoteAlbumEntityData,
|
||||
i1.$$RemoteAlbumEntityTableFilterComposer,
|
||||
i1.$$RemoteAlbumEntityTableOrderingComposer,
|
||||
i1.$$RemoteAlbumEntityTableAnnotationComposer,
|
||||
$$RemoteAlbumEntityTableCreateCompanionBuilder,
|
||||
$$RemoteAlbumEntityTableUpdateCompanionBuilder,
|
||||
(i1.RemoteAlbumEntityData, i1.$$RemoteAlbumEntityTableReferences),
|
||||
i1.RemoteAlbumEntityData,
|
||||
i0.PrefetchHooks Function({bool ownerId, bool thumbnailAssetId})>;
|
||||
|
||||
class $RemoteAlbumEntityTable extends i3.RemoteAlbumEntity
|
||||
with i0.TableInfo<$RemoteAlbumEntityTable, i1.RemoteAlbumEntityData> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$RemoteAlbumEntityTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> id = i0.GeneratedColumn<String>(
|
||||
'id', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _nameMeta =
|
||||
const i0.VerificationMeta('name');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> name = i0.GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _descriptionMeta =
|
||||
const i0.VerificationMeta('description');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> description =
|
||||
i0.GeneratedColumn<String>('description', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _createdAtMeta =
|
||||
const i0.VerificationMeta('createdAt');
|
||||
@override
|
||||
late final i0.GeneratedColumn<DateTime> createdAt =
|
||||
i0.GeneratedColumn<DateTime>('created_at', aliasedName, false,
|
||||
type: i0.DriftSqlType.dateTime,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: i4.currentDateAndTime);
|
||||
static const i0.VerificationMeta _updatedAtMeta =
|
||||
const i0.VerificationMeta('updatedAt');
|
||||
@override
|
||||
late final i0.GeneratedColumn<DateTime> updatedAt =
|
||||
i0.GeneratedColumn<DateTime>('updated_at', aliasedName, false,
|
||||
type: i0.DriftSqlType.dateTime,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: i4.currentDateAndTime);
|
||||
static const i0.VerificationMeta _ownerIdMeta =
|
||||
const i0.VerificationMeta('ownerId');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> ownerId = i0.GeneratedColumn<String>(
|
||||
'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
|
||||
late final i0.GeneratedColumn<String> thumbnailAssetId =
|
||||
i0.GeneratedColumn<String>('thumbnail_asset_id', aliasedName, true,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES remote_asset_entity (id) ON DELETE SET NULL'));
|
||||
static const i0.VerificationMeta _isActivityEnabledMeta =
|
||||
const i0.VerificationMeta('isActivityEnabled');
|
||||
@override
|
||||
late final i0.GeneratedColumn<bool> isActivityEnabled =
|
||||
i0.GeneratedColumn<bool>('is_activity_enabled', aliasedName, false,
|
||||
type: i0.DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("is_activity_enabled" IN (0, 1))'),
|
||||
defaultValue: const i4.Constant(true));
|
||||
@override
|
||||
late final i0.GeneratedColumnWithTypeConverter<i2.AssetOrder, int> order =
|
||||
i0.GeneratedColumn<int>('order', aliasedName, false,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: true)
|
||||
.withConverter<i2.AssetOrder>(
|
||||
i1.$RemoteAlbumEntityTable.$converterorder);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
ownerId,
|
||||
thumbnailAssetId,
|
||||
isActivityEnabled,
|
||||
order
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'remote_album_entity';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.RemoteAlbumEntityData> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = i0.VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('id')) {
|
||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_idMeta);
|
||||
}
|
||||
if (data.containsKey('name')) {
|
||||
context.handle(
|
||||
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_nameMeta);
|
||||
}
|
||||
if (data.containsKey('description')) {
|
||||
context.handle(
|
||||
_descriptionMeta,
|
||||
description.isAcceptableOrUnknown(
|
||||
data['description']!, _descriptionMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_descriptionMeta);
|
||||
}
|
||||
if (data.containsKey('created_at')) {
|
||||
context.handle(_createdAtMeta,
|
||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||
}
|
||||
if (data.containsKey('updated_at')) {
|
||||
context.handle(_updatedAtMeta,
|
||||
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,
|
||||
thumbnailAssetId.isAcceptableOrUnknown(
|
||||
data['thumbnail_asset_id']!, _thumbnailAssetIdMeta));
|
||||
}
|
||||
if (data.containsKey('is_activity_enabled')) {
|
||||
context.handle(
|
||||
_isActivityEnabledMeta,
|
||||
isActivityEnabled.isAcceptableOrUnknown(
|
||||
data['is_activity_enabled']!, _isActivityEnabledMeta));
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.RemoteAlbumEntityData map(Map<String, dynamic> data,
|
||||
{String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.RemoteAlbumEntityData(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||
name: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}name'])!,
|
||||
description: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}description'])!,
|
||||
createdAt: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
|
||||
updatedAt: attachedDatabase.typeMapping.read(
|
||||
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']),
|
||||
isActivityEnabled: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.bool, data['${effectivePrefix}is_activity_enabled'])!,
|
||||
order: i1.$RemoteAlbumEntityTable.$converterorder.fromSql(attachedDatabase
|
||||
.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}order'])!),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$RemoteAlbumEntityTable createAlias(String alias) {
|
||||
return $RemoteAlbumEntityTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static i0.JsonTypeConverter2<i2.AssetOrder, int, int> $converterorder =
|
||||
const i0.EnumIndexConverter<i2.AssetOrder>(i2.AssetOrder.values);
|
||||
@override
|
||||
bool get withoutRowId => true;
|
||||
@override
|
||||
bool get isStrict => true;
|
||||
}
|
||||
|
||||
class RemoteAlbumEntityData extends i0.DataClass
|
||||
implements i0.Insertable<i1.RemoteAlbumEntityData> {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final String ownerId;
|
||||
final String? thumbnailAssetId;
|
||||
final bool isActivityEnabled;
|
||||
final i2.AssetOrder order;
|
||||
const RemoteAlbumEntityData(
|
||||
{required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.ownerId,
|
||||
this.thumbnailAssetId,
|
||||
required this.isActivityEnabled,
|
||||
required this.order});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<String>(id);
|
||||
map['name'] = i0.Variable<String>(name);
|
||||
map['description'] = i0.Variable<String>(description);
|
||||
map['created_at'] = i0.Variable<DateTime>(createdAt);
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||
map['owner_id'] = i0.Variable<String>(ownerId);
|
||||
if (!nullToAbsent || thumbnailAssetId != null) {
|
||||
map['thumbnail_asset_id'] = i0.Variable<String>(thumbnailAssetId);
|
||||
}
|
||||
map['is_activity_enabled'] = i0.Variable<bool>(isActivityEnabled);
|
||||
{
|
||||
map['order'] = i0.Variable<int>(
|
||||
i1.$RemoteAlbumEntityTable.$converterorder.toSql(order));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
factory RemoteAlbumEntityData.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return RemoteAlbumEntityData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
name: serializer.fromJson<String>(json['name']),
|
||||
description: serializer.fromJson<String>(json['description']),
|
||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||
ownerId: serializer.fromJson<String>(json['ownerId']),
|
||||
thumbnailAssetId: serializer.fromJson<String?>(json['thumbnailAssetId']),
|
||||
isActivityEnabled: serializer.fromJson<bool>(json['isActivityEnabled']),
|
||||
order: i1.$RemoteAlbumEntityTable.$converterorder
|
||||
.fromJson(serializer.fromJson<int>(json['order'])),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'name': serializer.toJson<String>(name),
|
||||
'description': serializer.toJson<String>(description),
|
||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||
'ownerId': serializer.toJson<String>(ownerId),
|
||||
'thumbnailAssetId': serializer.toJson<String?>(thumbnailAssetId),
|
||||
'isActivityEnabled': serializer.toJson<bool>(isActivityEnabled),
|
||||
'order': serializer.toJson<int>(
|
||||
i1.$RemoteAlbumEntityTable.$converterorder.toJson(order)),
|
||||
};
|
||||
}
|
||||
|
||||
i1.RemoteAlbumEntityData copyWith(
|
||||
{String? id,
|
||||
String? name,
|
||||
String? description,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
String? ownerId,
|
||||
i0.Value<String?> thumbnailAssetId = const i0.Value.absent(),
|
||||
bool? isActivityEnabled,
|
||||
i2.AssetOrder? order}) =>
|
||||
i1.RemoteAlbumEntityData(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
ownerId: ownerId ?? this.ownerId,
|
||||
thumbnailAssetId: thumbnailAssetId.present
|
||||
? thumbnailAssetId.value
|
||||
: this.thumbnailAssetId,
|
||||
isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled,
|
||||
order: order ?? this.order,
|
||||
);
|
||||
RemoteAlbumEntityData copyWithCompanion(i1.RemoteAlbumEntityCompanion data) {
|
||||
return RemoteAlbumEntityData(
|
||||
id: data.id.present ? data.id.value : this.id,
|
||||
name: data.name.present ? data.name.value : this.name,
|
||||
description:
|
||||
data.description.present ? data.description.value : this.description,
|
||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||
updatedAt: data.updatedAt.present ? data.updatedAt.value : this.updatedAt,
|
||||
ownerId: data.ownerId.present ? data.ownerId.value : this.ownerId,
|
||||
thumbnailAssetId: data.thumbnailAssetId.present
|
||||
? data.thumbnailAssetId.value
|
||||
: this.thumbnailAssetId,
|
||||
isActivityEnabled: data.isActivityEnabled.present
|
||||
? data.isActivityEnabled.value
|
||||
: this.isActivityEnabled,
|
||||
order: data.order.present ? data.order.value : this.order,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('RemoteAlbumEntityData(')
|
||||
..write('id: $id, ')
|
||||
..write('name: $name, ')
|
||||
..write('description: $description, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('ownerId: $ownerId, ')
|
||||
..write('thumbnailAssetId: $thumbnailAssetId, ')
|
||||
..write('isActivityEnabled: $isActivityEnabled, ')
|
||||
..write('order: $order')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, name, description, createdAt, updatedAt,
|
||||
ownerId, thumbnailAssetId, isActivityEnabled, order);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.RemoteAlbumEntityData &&
|
||||
other.id == this.id &&
|
||||
other.name == this.name &&
|
||||
other.description == this.description &&
|
||||
other.createdAt == this.createdAt &&
|
||||
other.updatedAt == this.updatedAt &&
|
||||
other.ownerId == this.ownerId &&
|
||||
other.thumbnailAssetId == this.thumbnailAssetId &&
|
||||
other.isActivityEnabled == this.isActivityEnabled &&
|
||||
other.order == this.order);
|
||||
}
|
||||
|
||||
class RemoteAlbumEntityCompanion
|
||||
extends i0.UpdateCompanion<i1.RemoteAlbumEntityData> {
|
||||
final i0.Value<String> id;
|
||||
final i0.Value<String> name;
|
||||
final i0.Value<String> description;
|
||||
final i0.Value<DateTime> createdAt;
|
||||
final i0.Value<DateTime> updatedAt;
|
||||
final i0.Value<String> ownerId;
|
||||
final i0.Value<String?> thumbnailAssetId;
|
||||
final i0.Value<bool> isActivityEnabled;
|
||||
final i0.Value<i2.AssetOrder> order;
|
||||
const RemoteAlbumEntityCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.name = const i0.Value.absent(),
|
||||
this.description = const i0.Value.absent(),
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
this.updatedAt = const i0.Value.absent(),
|
||||
this.ownerId = const i0.Value.absent(),
|
||||
this.thumbnailAssetId = const i0.Value.absent(),
|
||||
this.isActivityEnabled = const i0.Value.absent(),
|
||||
this.order = const i0.Value.absent(),
|
||||
});
|
||||
RemoteAlbumEntityCompanion.insert({
|
||||
required String id,
|
||||
required String name,
|
||||
required String description,
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
this.updatedAt = const i0.Value.absent(),
|
||||
required String ownerId,
|
||||
this.thumbnailAssetId = const i0.Value.absent(),
|
||||
this.isActivityEnabled = const i0.Value.absent(),
|
||||
required i2.AssetOrder order,
|
||||
}) : id = i0.Value(id),
|
||||
name = i0.Value(name),
|
||||
description = i0.Value(description),
|
||||
ownerId = i0.Value(ownerId),
|
||||
order = i0.Value(order);
|
||||
static i0.Insertable<i1.RemoteAlbumEntityData> custom({
|
||||
i0.Expression<String>? id,
|
||||
i0.Expression<String>? name,
|
||||
i0.Expression<String>? description,
|
||||
i0.Expression<DateTime>? createdAt,
|
||||
i0.Expression<DateTime>? updatedAt,
|
||||
i0.Expression<String>? ownerId,
|
||||
i0.Expression<String>? thumbnailAssetId,
|
||||
i0.Expression<bool>? isActivityEnabled,
|
||||
i0.Expression<int>? order,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (name != null) 'name': name,
|
||||
if (description != null) 'description': description,
|
||||
if (createdAt != null) 'created_at': createdAt,
|
||||
if (updatedAt != null) 'updated_at': updatedAt,
|
||||
if (ownerId != null) 'owner_id': ownerId,
|
||||
if (thumbnailAssetId != null) 'thumbnail_asset_id': thumbnailAssetId,
|
||||
if (isActivityEnabled != null) 'is_activity_enabled': isActivityEnabled,
|
||||
if (order != null) 'order': order,
|
||||
});
|
||||
}
|
||||
|
||||
i1.RemoteAlbumEntityCompanion copyWith(
|
||||
{i0.Value<String>? id,
|
||||
i0.Value<String>? name,
|
||||
i0.Value<String>? description,
|
||||
i0.Value<DateTime>? createdAt,
|
||||
i0.Value<DateTime>? updatedAt,
|
||||
i0.Value<String>? ownerId,
|
||||
i0.Value<String?>? thumbnailAssetId,
|
||||
i0.Value<bool>? isActivityEnabled,
|
||||
i0.Value<i2.AssetOrder>? order}) {
|
||||
return i1.RemoteAlbumEntityCompanion(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
ownerId: ownerId ?? this.ownerId,
|
||||
thumbnailAssetId: thumbnailAssetId ?? this.thumbnailAssetId,
|
||||
isActivityEnabled: isActivityEnabled ?? this.isActivityEnabled,
|
||||
order: order ?? this.order,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<String>(id.value);
|
||||
}
|
||||
if (name.present) {
|
||||
map['name'] = i0.Variable<String>(name.value);
|
||||
}
|
||||
if (description.present) {
|
||||
map['description'] = i0.Variable<String>(description.value);
|
||||
}
|
||||
if (createdAt.present) {
|
||||
map['created_at'] = i0.Variable<DateTime>(createdAt.value);
|
||||
}
|
||||
if (updatedAt.present) {
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||
}
|
||||
if (ownerId.present) {
|
||||
map['owner_id'] = i0.Variable<String>(ownerId.value);
|
||||
}
|
||||
if (thumbnailAssetId.present) {
|
||||
map['thumbnail_asset_id'] = i0.Variable<String>(thumbnailAssetId.value);
|
||||
}
|
||||
if (isActivityEnabled.present) {
|
||||
map['is_activity_enabled'] = i0.Variable<bool>(isActivityEnabled.value);
|
||||
}
|
||||
if (order.present) {
|
||||
map['order'] = i0.Variable<int>(
|
||||
i1.$RemoteAlbumEntityTable.$converterorder.toSql(order.value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('RemoteAlbumEntityCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('name: $name, ')
|
||||
..write('description: $description, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('ownerId: $ownerId, ')
|
||||
..write('thumbnailAssetId: $thumbnailAssetId, ')
|
||||
..write('isActivityEnabled: $isActivityEnabled, ')
|
||||
..write('order: $order')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||
|
||||
class RemoteAlbumAssetEntity extends Table with DriftDefaultsMixin {
|
||||
const RemoteAlbumAssetEntity();
|
||||
|
||||
TextColumn get assetId =>
|
||||
text().references(RemoteAssetEntity, #id, onDelete: KeyAction.cascade)();
|
||||
|
||||
TextColumn get albumId =>
|
||||
text().references(RemoteAlbumEntity, #id, onDelete: KeyAction.cascade)();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {assetId, albumId};
|
||||
}
|
565
mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart
generated
Normal file
565
mobile/lib/infrastructure/entities/remote_album_asset.entity.drift.dart
generated
Normal file
@ -0,0 +1,565 @@
|
||||
// dart format width=80
|
||||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
|
||||
as i1;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart'
|
||||
as i2;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart'
|
||||
as i3;
|
||||
import 'package:drift/internal/modular.dart' as i4;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||
as i5;
|
||||
|
||||
typedef $$RemoteAlbumAssetEntityTableCreateCompanionBuilder
|
||||
= i1.RemoteAlbumAssetEntityCompanion Function({
|
||||
required String assetId,
|
||||
required String albumId,
|
||||
});
|
||||
typedef $$RemoteAlbumAssetEntityTableUpdateCompanionBuilder
|
||||
= i1.RemoteAlbumAssetEntityCompanion Function({
|
||||
i0.Value<String> assetId,
|
||||
i0.Value<String> albumId,
|
||||
});
|
||||
|
||||
final class $$RemoteAlbumAssetEntityTableReferences extends i0.BaseReferences<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumAssetEntityTable,
|
||||
i1.RemoteAlbumAssetEntityData> {
|
||||
$$RemoteAlbumAssetEntityTableReferences(
|
||||
super.$_db, super.$_table, super.$_typedResult);
|
||||
|
||||
static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumAssetEntityTable>(
|
||||
'remote_album_asset_entity')
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.id));
|
||||
|
||||
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
|
||||
final manager = i3
|
||||
.$$RemoteAssetEntityTableTableManager(
|
||||
$_db,
|
||||
i4.ReadDatabaseContainer($_db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_assetIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
|
||||
static i5.$RemoteAlbumEntityTable _albumIdTable(i0.GeneratedDatabase db) =>
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.createAlias(i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumAssetEntityTable>(
|
||||
'remote_album_asset_entity')
|
||||
.albumId,
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.id));
|
||||
|
||||
i5.$$RemoteAlbumEntityTableProcessedTableManager get albumId {
|
||||
final $_column = $_itemColumn<String>('album_id')!;
|
||||
|
||||
final manager = i5
|
||||
.$$RemoteAlbumEntityTableTableManager(
|
||||
$_db,
|
||||
i4.ReadDatabaseContainer($_db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity'))
|
||||
.filter((f) => f.id.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_albumIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return i0.ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumAssetEntityTableFilterComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumAssetEntityTable> {
|
||||
$$RemoteAlbumAssetEntityTableFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i3.$$RemoteAssetEntityTableFilterComposer get assetId {
|
||||
final i3.$$RemoteAssetEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i3.$$RemoteAssetEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i5.$$RemoteAlbumEntityTableFilterComposer get albumId {
|
||||
final i5.$$RemoteAlbumEntityTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$RemoteAlbumEntityTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumAssetEntityTableOrderingComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumAssetEntityTable> {
|
||||
$$RemoteAlbumAssetEntityTableOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i3.$$RemoteAssetEntityTableOrderingComposer get assetId {
|
||||
final i3.$$RemoteAssetEntityTableOrderingComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i3.$$RemoteAssetEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>(
|
||||
'remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i5.$$RemoteAlbumEntityTableOrderingComposer get albumId {
|
||||
final i5.$$RemoteAlbumEntityTableOrderingComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$RemoteAlbumEntityTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>(
|
||||
'remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumAssetEntityTableAnnotationComposer
|
||||
extends i0.Composer<i0.GeneratedDatabase, i1.$RemoteAlbumAssetEntityTable> {
|
||||
$$RemoteAlbumAssetEntityTableAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
i3.$$RemoteAssetEntityTableAnnotationComposer get assetId {
|
||||
final i3.$$RemoteAssetEntityTableAnnotationComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.assetId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i3.$$RemoteAssetEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>(
|
||||
'remote_asset_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
i5.$$RemoteAlbumEntityTableAnnotationComposer get albumId {
|
||||
final i5.$$RemoteAlbumEntityTableAnnotationComposer composer =
|
||||
$composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.albumId,
|
||||
referencedTable: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity'),
|
||||
getReferencedColumn: (t) => t.id,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
i5.$$RemoteAlbumEntityTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: i4.ReadDatabaseContainer($db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>(
|
||||
'remote_album_entity'),
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$RemoteAlbumAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumAssetEntityTable,
|
||||
i1.RemoteAlbumAssetEntityData,
|
||||
i1.$$RemoteAlbumAssetEntityTableFilterComposer,
|
||||
i1.$$RemoteAlbumAssetEntityTableOrderingComposer,
|
||||
i1.$$RemoteAlbumAssetEntityTableAnnotationComposer,
|
||||
$$RemoteAlbumAssetEntityTableCreateCompanionBuilder,
|
||||
$$RemoteAlbumAssetEntityTableUpdateCompanionBuilder,
|
||||
(i1.RemoteAlbumAssetEntityData, i1.$$RemoteAlbumAssetEntityTableReferences),
|
||||
i1.RemoteAlbumAssetEntityData,
|
||||
i0.PrefetchHooks Function({bool assetId, bool albumId})> {
|
||||
$$RemoteAlbumAssetEntityTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$RemoteAlbumAssetEntityTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
i1.$$RemoteAlbumAssetEntityTableFilterComposer(
|
||||
$db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
i1.$$RemoteAlbumAssetEntityTableOrderingComposer(
|
||||
$db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
i1.$$RemoteAlbumAssetEntityTableAnnotationComposer(
|
||||
$db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
i0.Value<String> assetId = const i0.Value.absent(),
|
||||
i0.Value<String> albumId = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.RemoteAlbumAssetEntityCompanion(
|
||||
assetId: assetId,
|
||||
albumId: albumId,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String assetId,
|
||||
required String albumId,
|
||||
}) =>
|
||||
i1.RemoteAlbumAssetEntityCompanion.insert(
|
||||
assetId: assetId,
|
||||
albumId: albumId,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) => (
|
||||
e.readTable(table),
|
||||
i1.$$RemoteAlbumAssetEntityTableReferences(db, table, e)
|
||||
))
|
||||
.toList(),
|
||||
prefetchHooksCallback: ({assetId = false, albumId = false}) {
|
||||
return i0.PrefetchHooks(
|
||||
db: db,
|
||||
explicitlyWatchedTables: [],
|
||||
addJoins: <
|
||||
T extends i0.TableManagerState<
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic,
|
||||
dynamic>>(state) {
|
||||
if (assetId) {
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.assetId,
|
||||
referencedTable: i1.$$RemoteAlbumAssetEntityTableReferences
|
||||
._assetIdTable(db),
|
||||
referencedColumn: i1.$$RemoteAlbumAssetEntityTableReferences
|
||||
._assetIdTable(db)
|
||||
.id,
|
||||
) as T;
|
||||
}
|
||||
if (albumId) {
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.albumId,
|
||||
referencedTable: i1.$$RemoteAlbumAssetEntityTableReferences
|
||||
._albumIdTable(db),
|
||||
referencedColumn: i1.$$RemoteAlbumAssetEntityTableReferences
|
||||
._albumIdTable(db)
|
||||
.id,
|
||||
) as T;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
getPrefetchedDataCallback: (items) async {
|
||||
return [];
|
||||
},
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
typedef $$RemoteAlbumAssetEntityTableProcessedTableManager
|
||||
= i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$RemoteAlbumAssetEntityTable,
|
||||
i1.RemoteAlbumAssetEntityData,
|
||||
i1.$$RemoteAlbumAssetEntityTableFilterComposer,
|
||||
i1.$$RemoteAlbumAssetEntityTableOrderingComposer,
|
||||
i1.$$RemoteAlbumAssetEntityTableAnnotationComposer,
|
||||
$$RemoteAlbumAssetEntityTableCreateCompanionBuilder,
|
||||
$$RemoteAlbumAssetEntityTableUpdateCompanionBuilder,
|
||||
(
|
||||
i1.RemoteAlbumAssetEntityData,
|
||||
i1.$$RemoteAlbumAssetEntityTableReferences
|
||||
),
|
||||
i1.RemoteAlbumAssetEntityData,
|
||||
i0.PrefetchHooks Function({bool assetId, bool albumId})>;
|
||||
|
||||
class $RemoteAlbumAssetEntityTable extends i2.RemoteAlbumAssetEntity
|
||||
with
|
||||
i0.TableInfo<$RemoteAlbumAssetEntityTable,
|
||||
i1.RemoteAlbumAssetEntityData> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$RemoteAlbumAssetEntityTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _assetIdMeta =
|
||||
const i0.VerificationMeta('assetId');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> assetId = i0.GeneratedColumn<String>(
|
||||
'asset_id', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES remote_asset_entity (id) ON DELETE CASCADE'));
|
||||
static const i0.VerificationMeta _albumIdMeta =
|
||||
const i0.VerificationMeta('albumId');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> albumId = i0.GeneratedColumn<String>(
|
||||
'album_id', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES remote_album_entity (id) ON DELETE CASCADE'));
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [assetId, albumId];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'remote_album_asset_entity';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.RemoteAlbumAssetEntityData> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = i0.VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('asset_id')) {
|
||||
context.handle(_assetIdMeta,
|
||||
assetId.isAcceptableOrUnknown(data['asset_id']!, _assetIdMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_assetIdMeta);
|
||||
}
|
||||
if (data.containsKey('album_id')) {
|
||||
context.handle(_albumIdMeta,
|
||||
albumId.isAcceptableOrUnknown(data['album_id']!, _albumIdMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_albumIdMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {assetId, albumId};
|
||||
@override
|
||||
i1.RemoteAlbumAssetEntityData map(Map<String, dynamic> data,
|
||||
{String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.RemoteAlbumAssetEntityData(
|
||||
assetId: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}asset_id'])!,
|
||||
albumId: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}album_id'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$RemoteAlbumAssetEntityTable createAlias(String alias) {
|
||||
return $RemoteAlbumAssetEntityTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get withoutRowId => true;
|
||||
@override
|
||||
bool get isStrict => true;
|
||||
}
|
||||
|
||||
class RemoteAlbumAssetEntityData extends i0.DataClass
|
||||
implements i0.Insertable<i1.RemoteAlbumAssetEntityData> {
|
||||
final String assetId;
|
||||
final String albumId;
|
||||
const RemoteAlbumAssetEntityData(
|
||||
{required this.assetId, required this.albumId});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['asset_id'] = i0.Variable<String>(assetId);
|
||||
map['album_id'] = i0.Variable<String>(albumId);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory RemoteAlbumAssetEntityData.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return RemoteAlbumAssetEntityData(
|
||||
assetId: serializer.fromJson<String>(json['assetId']),
|
||||
albumId: serializer.fromJson<String>(json['albumId']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'assetId': serializer.toJson<String>(assetId),
|
||||
'albumId': serializer.toJson<String>(albumId),
|
||||
};
|
||||
}
|
||||
|
||||
i1.RemoteAlbumAssetEntityData copyWith({String? assetId, String? albumId}) =>
|
||||
i1.RemoteAlbumAssetEntityData(
|
||||
assetId: assetId ?? this.assetId,
|
||||
albumId: albumId ?? this.albumId,
|
||||
);
|
||||
RemoteAlbumAssetEntityData copyWithCompanion(
|
||||
i1.RemoteAlbumAssetEntityCompanion data) {
|
||||
return RemoteAlbumAssetEntityData(
|
||||
assetId: data.assetId.present ? data.assetId.value : this.assetId,
|
||||
albumId: data.albumId.present ? data.albumId.value : this.albumId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('RemoteAlbumAssetEntityData(')
|
||||
..write('assetId: $assetId, ')
|
||||
..write('albumId: $albumId')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(assetId, albumId);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.RemoteAlbumAssetEntityData &&
|
||||
other.assetId == this.assetId &&
|
||||
other.albumId == this.albumId);
|
||||
}
|
||||
|
||||
class RemoteAlbumAssetEntityCompanion
|
||||
extends i0.UpdateCompanion<i1.RemoteAlbumAssetEntityData> {
|
||||
final i0.Value<String> assetId;
|
||||
final i0.Value<String> albumId;
|
||||
const RemoteAlbumAssetEntityCompanion({
|
||||
this.assetId = const i0.Value.absent(),
|
||||
this.albumId = const i0.Value.absent(),
|
||||
});
|
||||
RemoteAlbumAssetEntityCompanion.insert({
|
||||
required String assetId,
|
||||
required String albumId,
|
||||
}) : assetId = i0.Value(assetId),
|
||||
albumId = i0.Value(albumId);
|
||||
static i0.Insertable<i1.RemoteAlbumAssetEntityData> custom({
|
||||
i0.Expression<String>? assetId,
|
||||
i0.Expression<String>? albumId,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (assetId != null) 'asset_id': assetId,
|
||||
if (albumId != null) 'album_id': albumId,
|
||||
});
|
||||
}
|
||||
|
||||
i1.RemoteAlbumAssetEntityCompanion copyWith(
|
||||
{i0.Value<String>? assetId, i0.Value<String>? albumId}) {
|
||||
return i1.RemoteAlbumAssetEntityCompanion(
|
||||
assetId: assetId ?? this.assetId,
|
||||
albumId: albumId ?? this.albumId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (assetId.present) {
|
||||
map['asset_id'] = i0.Variable<String>(assetId.value);
|
||||
}
|
||||
if (albumId.present) {
|
||||
map['album_id'] = i0.Variable<String>(albumId.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('RemoteAlbumAssetEntityCompanion(')
|
||||
..write('assetId: $assetId, ')
|
||||
..write('albumId: $albumId')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ typedef $$RemoteAssetEntityTableCreateCompanionBuilder
|
||||
required i2.AssetType type,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
i0.Value<int?> width,
|
||||
i0.Value<int?> height,
|
||||
i0.Value<int?> durationInSeconds,
|
||||
required String id,
|
||||
required String checksum,
|
||||
@ -33,6 +35,8 @@ typedef $$RemoteAssetEntityTableUpdateCompanionBuilder
|
||||
i0.Value<i2.AssetType> type,
|
||||
i0.Value<DateTime> createdAt,
|
||||
i0.Value<DateTime> updatedAt,
|
||||
i0.Value<int?> width,
|
||||
i0.Value<int?> height,
|
||||
i0.Value<int?> durationInSeconds,
|
||||
i0.Value<String> id,
|
||||
i0.Value<String> checksum,
|
||||
@ -101,6 +105,12 @@ class $$RemoteAssetEntityTableFilterComposer
|
||||
i0.ColumnFilters<DateTime> get updatedAt => $composableBuilder(
|
||||
column: $table.updatedAt, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get width => $composableBuilder(
|
||||
column: $table.width, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get height => $composableBuilder(
|
||||
column: $table.height, builder: (column) => i0.ColumnFilters(column));
|
||||
|
||||
i0.ColumnFilters<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds,
|
||||
builder: (column) => i0.ColumnFilters(column));
|
||||
@ -175,6 +185,12 @@ class $$RemoteAssetEntityTableOrderingComposer
|
||||
column: $table.updatedAt,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get width => $composableBuilder(
|
||||
column: $table.width, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get height => $composableBuilder(
|
||||
column: $table.height, builder: (column) => i0.ColumnOrderings(column));
|
||||
|
||||
i0.ColumnOrderings<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds,
|
||||
builder: (column) => i0.ColumnOrderings(column));
|
||||
@ -249,6 +265,12 @@ class $$RemoteAssetEntityTableAnnotationComposer
|
||||
i0.GeneratedColumn<DateTime> get updatedAt =>
|
||||
$composableBuilder(column: $table.updatedAt, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get width =>
|
||||
$composableBuilder(column: $table.width, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get height =>
|
||||
$composableBuilder(column: $table.height, builder: (column) => column);
|
||||
|
||||
i0.GeneratedColumn<int> get durationInSeconds => $composableBuilder(
|
||||
column: $table.durationInSeconds, builder: (column) => column);
|
||||
|
||||
@ -326,6 +348,8 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
i0.Value<i2.AssetType> type = const i0.Value.absent(),
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
i0.Value<String> id = const i0.Value.absent(),
|
||||
i0.Value<String> checksum = const i0.Value.absent(),
|
||||
@ -341,6 +365,8 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
type: type,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds,
|
||||
id: id,
|
||||
checksum: checksum,
|
||||
@ -356,6 +382,8 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
required i2.AssetType type,
|
||||
i0.Value<DateTime> createdAt = const i0.Value.absent(),
|
||||
i0.Value<DateTime> updatedAt = const i0.Value.absent(),
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
required String id,
|
||||
required String checksum,
|
||||
@ -371,6 +399,8 @@ class $$RemoteAssetEntityTableTableManager extends i0.RootTableManager<
|
||||
type: type,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds,
|
||||
id: id,
|
||||
checksum: checksum,
|
||||
@ -477,6 +507,18 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
||||
type: i0.DriftSqlType.dateTime,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: i4.currentDateAndTime);
|
||||
static const i0.VerificationMeta _widthMeta =
|
||||
const i0.VerificationMeta('width');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> width = i0.GeneratedColumn<int>(
|
||||
'width', aliasedName, true,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||
static const i0.VerificationMeta _heightMeta =
|
||||
const i0.VerificationMeta('height');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> height = i0.GeneratedColumn<int>(
|
||||
'height', aliasedName, true,
|
||||
type: i0.DriftSqlType.int, requiredDuringInsert: false);
|
||||
static const i0.VerificationMeta _durationInSecondsMeta =
|
||||
const i0.VerificationMeta('durationInSeconds');
|
||||
@override
|
||||
@ -543,6 +585,8 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
id,
|
||||
checksum,
|
||||
@ -578,6 +622,14 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
||||
context.handle(_updatedAtMeta,
|
||||
updatedAt.isAcceptableOrUnknown(data['updated_at']!, _updatedAtMeta));
|
||||
}
|
||||
if (data.containsKey('width')) {
|
||||
context.handle(
|
||||
_widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta));
|
||||
}
|
||||
if (data.containsKey('height')) {
|
||||
context.handle(_heightMeta,
|
||||
height.isAcceptableOrUnknown(data['height']!, _heightMeta));
|
||||
}
|
||||
if (data.containsKey('duration_in_seconds')) {
|
||||
context.handle(
|
||||
_durationInSecondsMeta,
|
||||
@ -640,6 +692,10 @@ class $RemoteAssetEntityTable extends i3.RemoteAssetEntity
|
||||
i0.DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
|
||||
updatedAt: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.dateTime, data['${effectivePrefix}updated_at'])!,
|
||||
width: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}width']),
|
||||
height: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}height']),
|
||||
durationInSeconds: attachedDatabase.typeMapping.read(
|
||||
i0.DriftSqlType.int, data['${effectivePrefix}duration_in_seconds']),
|
||||
id: attachedDatabase.typeMapping
|
||||
@ -684,6 +740,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
final i2.AssetType type;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final int? width;
|
||||
final int? height;
|
||||
final int? durationInSeconds;
|
||||
final String id;
|
||||
final String checksum;
|
||||
@ -698,6 +756,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
required this.type,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
this.width,
|
||||
this.height,
|
||||
this.durationInSeconds,
|
||||
required this.id,
|
||||
required this.checksum,
|
||||
@ -717,6 +777,12 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
}
|
||||
map['created_at'] = i0.Variable<DateTime>(createdAt);
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt);
|
||||
if (!nullToAbsent || width != null) {
|
||||
map['width'] = i0.Variable<int>(width);
|
||||
}
|
||||
if (!nullToAbsent || height != null) {
|
||||
map['height'] = i0.Variable<int>(height);
|
||||
}
|
||||
if (!nullToAbsent || durationInSeconds != null) {
|
||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds);
|
||||
}
|
||||
@ -749,6 +815,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
.fromJson(serializer.fromJson<int>(json['type'])),
|
||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||
updatedAt: serializer.fromJson<DateTime>(json['updatedAt']),
|
||||
width: serializer.fromJson<int?>(json['width']),
|
||||
height: serializer.fromJson<int?>(json['height']),
|
||||
durationInSeconds: serializer.fromJson<int?>(json['durationInSeconds']),
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
checksum: serializer.fromJson<String>(json['checksum']),
|
||||
@ -770,6 +838,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
.toJson<int>(i1.$RemoteAssetEntityTable.$convertertype.toJson(type)),
|
||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||
'updatedAt': serializer.toJson<DateTime>(updatedAt),
|
||||
'width': serializer.toJson<int?>(width),
|
||||
'height': serializer.toJson<int?>(height),
|
||||
'durationInSeconds': serializer.toJson<int?>(durationInSeconds),
|
||||
'id': serializer.toJson<String>(id),
|
||||
'checksum': serializer.toJson<String>(checksum),
|
||||
@ -788,6 +858,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
i2.AssetType? type,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
i0.Value<int?> width = const i0.Value.absent(),
|
||||
i0.Value<int?> height = const i0.Value.absent(),
|
||||
i0.Value<int?> durationInSeconds = const i0.Value.absent(),
|
||||
String? id,
|
||||
String? checksum,
|
||||
@ -802,6 +874,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
type: type ?? this.type,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
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,
|
||||
@ -821,6 +895,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
type: data.type.present ? data.type.value : this.type,
|
||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||
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,
|
||||
@ -846,6 +922,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
..write('type: $type, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('width: $width, ')
|
||||
..write('height: $height, ')
|
||||
..write('durationInSeconds: $durationInSeconds, ')
|
||||
..write('id: $id, ')
|
||||
..write('checksum: $checksum, ')
|
||||
@ -865,6 +943,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
id,
|
||||
checksum,
|
||||
@ -882,6 +962,8 @@ class RemoteAssetEntityData extends i0.DataClass
|
||||
other.type == this.type &&
|
||||
other.createdAt == this.createdAt &&
|
||||
other.updatedAt == this.updatedAt &&
|
||||
other.width == this.width &&
|
||||
other.height == this.height &&
|
||||
other.durationInSeconds == this.durationInSeconds &&
|
||||
other.id == this.id &&
|
||||
other.checksum == this.checksum &&
|
||||
@ -899,6 +981,8 @@ class RemoteAssetEntityCompanion
|
||||
final i0.Value<i2.AssetType> type;
|
||||
final i0.Value<DateTime> createdAt;
|
||||
final i0.Value<DateTime> updatedAt;
|
||||
final i0.Value<int?> width;
|
||||
final i0.Value<int?> height;
|
||||
final i0.Value<int?> durationInSeconds;
|
||||
final i0.Value<String> id;
|
||||
final i0.Value<String> checksum;
|
||||
@ -913,6 +997,8 @@ class RemoteAssetEntityCompanion
|
||||
this.type = const i0.Value.absent(),
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
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.id = const i0.Value.absent(),
|
||||
this.checksum = const i0.Value.absent(),
|
||||
@ -928,6 +1014,8 @@ class RemoteAssetEntityCompanion
|
||||
required i2.AssetType type,
|
||||
this.createdAt = const i0.Value.absent(),
|
||||
this.updatedAt = const i0.Value.absent(),
|
||||
this.width = const i0.Value.absent(),
|
||||
this.height = const i0.Value.absent(),
|
||||
this.durationInSeconds = const i0.Value.absent(),
|
||||
required String id,
|
||||
required String checksum,
|
||||
@ -948,6 +1036,8 @@ class RemoteAssetEntityCompanion
|
||||
i0.Expression<int>? type,
|
||||
i0.Expression<DateTime>? createdAt,
|
||||
i0.Expression<DateTime>? updatedAt,
|
||||
i0.Expression<int>? width,
|
||||
i0.Expression<int>? height,
|
||||
i0.Expression<int>? durationInSeconds,
|
||||
i0.Expression<String>? id,
|
||||
i0.Expression<String>? checksum,
|
||||
@ -963,6 +1053,8 @@ class RemoteAssetEntityCompanion
|
||||
if (type != null) 'type': type,
|
||||
if (createdAt != null) 'created_at': createdAt,
|
||||
if (updatedAt != null) 'updated_at': updatedAt,
|
||||
if (width != null) 'width': width,
|
||||
if (height != null) 'height': height,
|
||||
if (durationInSeconds != null) 'duration_in_seconds': durationInSeconds,
|
||||
if (id != null) 'id': id,
|
||||
if (checksum != null) 'checksum': checksum,
|
||||
@ -980,6 +1072,8 @@ class RemoteAssetEntityCompanion
|
||||
i0.Value<i2.AssetType>? type,
|
||||
i0.Value<DateTime>? createdAt,
|
||||
i0.Value<DateTime>? updatedAt,
|
||||
i0.Value<int?>? width,
|
||||
i0.Value<int?>? height,
|
||||
i0.Value<int?>? durationInSeconds,
|
||||
i0.Value<String>? id,
|
||||
i0.Value<String>? checksum,
|
||||
@ -994,6 +1088,8 @@ class RemoteAssetEntityCompanion
|
||||
type: type ?? this.type,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
width: width ?? this.width,
|
||||
height: height ?? this.height,
|
||||
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
|
||||
id: id ?? this.id,
|
||||
checksum: checksum ?? this.checksum,
|
||||
@ -1022,6 +1118,12 @@ class RemoteAssetEntityCompanion
|
||||
if (updatedAt.present) {
|
||||
map['updated_at'] = i0.Variable<DateTime>(updatedAt.value);
|
||||
}
|
||||
if (width.present) {
|
||||
map['width'] = i0.Variable<int>(width.value);
|
||||
}
|
||||
if (height.present) {
|
||||
map['height'] = i0.Variable<int>(height.value);
|
||||
}
|
||||
if (durationInSeconds.present) {
|
||||
map['duration_in_seconds'] = i0.Variable<int>(durationInSeconds.value);
|
||||
}
|
||||
@ -1061,6 +1163,8 @@ class RemoteAssetEntityCompanion
|
||||
..write('type: $type, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('updatedAt: $updatedAt, ')
|
||||
..write('width: $width, ')
|
||||
..write('height: $height, ')
|
||||
..write('durationInSeconds: $durationInSeconds, ')
|
||||
..write('id: $id, ')
|
||||
..write('checksum: $checksum, ')
|
||||
|
@ -3,12 +3,15 @@ import 'dart:async';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_flutter/drift_flutter.dart';
|
||||
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/album_user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_album_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user_metadata.entity.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
@ -38,8 +41,11 @@ class IsarDatabaseRepository implements IDatabaseRepository {
|
||||
LocalAlbumEntity,
|
||||
LocalAssetEntity,
|
||||
LocalAlbumAssetEntity,
|
||||
RemoteAssetEntity,
|
||||
RemoteExifEntity,
|
||||
RemoteAssetEntity,
|
||||
RemoteAlbumEntity,
|
||||
RemoteAlbumAssetEntity,
|
||||
AlbumUserEntity,
|
||||
],
|
||||
)
|
||||
class Drift extends $Drift implements IDatabaseRepository {
|
||||
|
@ -17,6 +17,12 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.
|
||||
as i7;
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart'
|
||||
as i8;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart'
|
||||
as i9;
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart'
|
||||
as i10;
|
||||
import 'package:immich_mobile/infrastructure/entities/album_user.entity.drift.dart'
|
||||
as i11;
|
||||
|
||||
abstract class $Drift extends i0.GeneratedDatabase {
|
||||
$Drift(i0.QueryExecutor e) : super(e);
|
||||
@ -36,6 +42,12 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
i7.$RemoteAssetEntityTable(this);
|
||||
late final i8.$RemoteExifEntityTable remoteExifEntity =
|
||||
i8.$RemoteExifEntityTable(this);
|
||||
late final i9.$RemoteAlbumEntityTable remoteAlbumEntity =
|
||||
i9.$RemoteAlbumEntityTable(this);
|
||||
late final i10.$RemoteAlbumAssetEntityTable remoteAlbumAssetEntity =
|
||||
i10.$RemoteAlbumAssetEntityTable(this);
|
||||
late final i11.$AlbumUserEntityTable albumUserEntity =
|
||||
i11.$AlbumUserEntityTable(this);
|
||||
@override
|
||||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>();
|
||||
@ -49,6 +61,9 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
localAlbumAssetEntity,
|
||||
remoteAssetEntity,
|
||||
remoteExifEntity,
|
||||
remoteAlbumEntity,
|
||||
remoteAlbumAssetEntity,
|
||||
albumUserEntity,
|
||||
i5.idxLocalAssetChecksum,
|
||||
i7.uQRemoteAssetOwnerChecksum
|
||||
];
|
||||
@ -108,6 +123,50 @@ abstract class $Drift extends i0.GeneratedDatabase {
|
||||
i0.TableUpdate('remote_exif_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_entity', kind: i0.UpdateKind.update),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_asset_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_asset_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_album_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('remote_album_asset_entity',
|
||||
kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('remote_album_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('album_user_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
i0.WritePropagation(
|
||||
on: i0.TableUpdateQuery.onTableName('user_entity',
|
||||
limitUpdateKind: i0.UpdateKind.delete),
|
||||
result: [
|
||||
i0.TableUpdate('album_user_entity', kind: i0.UpdateKind.delete),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@override
|
||||
@ -134,4 +193,11 @@ class $DriftManager {
|
||||
i7.$$RemoteAssetEntityTableTableManager(_db, _db.remoteAssetEntity);
|
||||
i8.$$RemoteExifEntityTableTableManager get remoteExifEntity =>
|
||||
i8.$$RemoteExifEntityTableTableManager(_db, _db.remoteExifEntity);
|
||||
i9.$$RemoteAlbumEntityTableTableManager get remoteAlbumEntity =>
|
||||
i9.$$RemoteAlbumEntityTableTableManager(_db, _db.remoteAlbumEntity);
|
||||
i10.$$RemoteAlbumAssetEntityTableTableManager get remoteAlbumAssetEntity =>
|
||||
i10.$$RemoteAlbumAssetEntityTableTableManager(
|
||||
_db, _db.remoteAlbumAssetEntity);
|
||||
i11.$$AlbumUserEntityTableTableManager get albumUserEntity =>
|
||||
i11.$$AlbumUserEntityTableTableManager(_db, _db.albumUserEntity);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
super(_db);
|
||||
|
||||
@override
|
||||
Future<List<LocalAlbum>> getAll({SortLocalAlbumsBy? sortBy}) {
|
||||
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
||||
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
||||
|
||||
final query = _db.localAlbumEntity.select().join([
|
||||
@ -30,9 +30,23 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
query
|
||||
..addColumns([assetCount])
|
||||
..groupBy([_db.localAlbumEntity.id]);
|
||||
if (sortBy == SortLocalAlbumsBy.id) {
|
||||
query.orderBy([OrderingTerm.asc(_db.localAlbumEntity.id)]);
|
||||
|
||||
if (sortBy.isNotEmpty) {
|
||||
final orderings = <OrderingTerm>[];
|
||||
for (final sort in sortBy) {
|
||||
orderings.add(
|
||||
switch (sort) {
|
||||
SortLocalAlbumsBy.id => OrderingTerm.asc(_db.localAlbumEntity.id),
|
||||
SortLocalAlbumsBy.backupSelection =>
|
||||
OrderingTerm.asc(_db.localAlbumEntity.backupSelection),
|
||||
SortLocalAlbumsBy.isIosSharedAlbum =>
|
||||
OrderingTerm.asc(_db.localAlbumEntity.isIosSharedAlbum),
|
||||
},
|
||||
);
|
||||
}
|
||||
query.orderBy(orderings);
|
||||
}
|
||||
|
||||
return query
|
||||
.map(
|
||||
(row) => row
|
||||
@ -49,7 +63,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
// That is not the case on Android since asset <-> album has one:one mapping
|
||||
final assetsToDelete = _platform.isIOS
|
||||
? await _getUniqueAssetsInAlbum(albumId)
|
||||
: await getAssetIdsForAlbum(albumId);
|
||||
: await getAssetIds(albumId);
|
||||
await _deleteAssets(assetsToDelete);
|
||||
|
||||
// All the other assets that are still associated will be unlinked automatically on-cascade
|
||||
@ -59,7 +73,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
});
|
||||
|
||||
@override
|
||||
Future<void> syncAlbumDeletes(
|
||||
Future<void> syncDeletes(
|
||||
String albumId,
|
||||
Iterable<String> assetIdsToKeep,
|
||||
) async {
|
||||
@ -172,7 +186,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LocalAsset>> getAssetsForAlbum(String albumId) {
|
||||
Future<List<LocalAsset>> getAssets(String albumId) {
|
||||
final query = _db.localAlbumAssetEntity.select().join(
|
||||
[
|
||||
innerJoin(
|
||||
@ -189,7 +203,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getAssetIdsForAlbum(String albumId) {
|
||||
Future<List<String>> getAssetIds(String albumId) {
|
||||
final query = _db.localAlbumAssetEntity.selectOnly()
|
||||
..addColumns([_db.localAlbumAssetEntity.assetId])
|
||||
..where(_db.localAlbumAssetEntity.albumId.equals(albumId));
|
||||
@ -272,7 +286,9 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
type: asset.type,
|
||||
createdAt: Value(asset.createdAt),
|
||||
updatedAt: Value(asset.updatedAt),
|
||||
durationInSeconds: Value.absentIfNull(asset.durationInSeconds),
|
||||
width: Value(asset.width),
|
||||
height: Value(asset.height),
|
||||
durationInSeconds: Value(asset.durationInSeconds),
|
||||
id: asset.id,
|
||||
checksum: const Value(null),
|
||||
);
|
||||
|
@ -22,7 +22,7 @@ class IsarStoreRepository extends IsarDatabaseRepository
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<StoreUpdateEvent> watchAll() {
|
||||
Stream<StoreDto<Object>> watchAll() {
|
||||
return _db.storeValues
|
||||
.filter()
|
||||
.anyOf(validStoreKeys, (query, id) => query.idEqualTo(id))
|
||||
@ -71,10 +71,11 @@ class IsarStoreRepository extends IsarDatabaseRepository
|
||||
.asyncMap((e) async => e == null ? null : await _toValue(key, e));
|
||||
}
|
||||
|
||||
Future<StoreUpdateEvent> _toUpdateEvent(StoreValue entity) async {
|
||||
final key = StoreKey.values.firstWhere((e) => e.id == entity.id);
|
||||
Future<StoreDto<Object>> _toUpdateEvent(StoreValue entity) async {
|
||||
final key = StoreKey.values.firstWhere((e) => e.id == entity.id)
|
||||
as StoreKey<Object>;
|
||||
final value = await _toValue(key, entity);
|
||||
return StoreUpdateEvent(key, value);
|
||||
return StoreDto(key, value);
|
||||
}
|
||||
|
||||
Future<T?> _toValue<T>(StoreKey<T> key, StoreValue entity) async =>
|
||||
@ -107,4 +108,13 @@ class IsarStoreRepository extends IsarDatabaseRepository
|
||||
};
|
||||
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<StoreDto<Object>>> getAll() async {
|
||||
final entities = await _db.storeValues
|
||||
.filter()
|
||||
.anyOf(validStoreKeys, (query, id) => query.idEqualTo(id))
|
||||
.findAll();
|
||||
return Future.wait(entities.map((e) => _toUpdateEvent(e)).toList());
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ class SyncApiRepository implements ISyncApiRepository {
|
||||
SyncRequestType.partnerAssetsV1,
|
||||
SyncRequestType.assetExifsV1,
|
||||
SyncRequestType.partnerAssetExifsV1,
|
||||
SyncRequestType.albumsV1,
|
||||
// SyncRequestType.albumAssetsV1,
|
||||
SyncRequestType.albumUsersV1,
|
||||
],
|
||||
).toJson(),
|
||||
);
|
||||
@ -65,8 +68,7 @@ class SyncApiRepository implements ISyncApiRepository {
|
||||
}
|
||||
|
||||
try {
|
||||
final response =
|
||||
await client.send(request).timeout(const Duration(seconds: 20));
|
||||
final response = await client.send(request);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
final errorBody = await response.stream.bytesToString();
|
||||
@ -130,8 +132,7 @@ class SyncApiRepository implements ISyncApiRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: avoid-dynamic
|
||||
const _kResponseMap = <SyncEntityType, Function(dynamic)>{
|
||||
const _kResponseMap = <SyncEntityType, Function(Object)>{
|
||||
SyncEntityType.userV1: SyncUserV1.fromJson,
|
||||
SyncEntityType.userDeleteV1: SyncUserDeleteV1.fromJson,
|
||||
SyncEntityType.partnerV1: SyncPartnerV1.fromJson,
|
||||
@ -142,4 +143,10 @@ const _kResponseMap = <SyncEntityType, Function(dynamic)>{
|
||||
SyncEntityType.partnerAssetV1: SyncAssetV1.fromJson,
|
||||
SyncEntityType.partnerAssetDeleteV1: SyncAssetDeleteV1.fromJson,
|
||||
SyncEntityType.partnerAssetExifV1: SyncAssetExifV1.fromJson,
|
||||
SyncEntityType.albumV1: SyncAlbumV1.fromJson,
|
||||
SyncEntityType.albumDeleteV1: SyncAlbumDeleteV1.fromJson,
|
||||
// SyncEntityType.albumAssetV1: SyncAlbumAssetV1.fromJson,
|
||||
// SyncEntityType.albumAssetDeleteV1: SyncAlbumAssetDeleteV1.fromJson,
|
||||
SyncEntityType.albumUserV1: SyncAlbumUserV1.fromJson,
|
||||
SyncEntityType.albumUserDeleteV1: SyncAlbumUserDeleteV1.fromJson,
|
||||
};
|
||||
|
@ -3,12 +3,19 @@ import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
|
||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/album_user.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/album_user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_album.entity.drift.dart';
|
||||
// import 'package:immich_mobile/infrastructure/entities/remote_album_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/user.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart' as api show AssetVisibility;
|
||||
import 'package:openapi/api.dart' hide AssetVisibility;
|
||||
import 'package:openapi/api.dart' as api
|
||||
show AssetVisibility, AssetOrder, AlbumUserRole;
|
||||
import 'package:openapi/api.dart'
|
||||
hide AssetVisibility, AssetOrder, AlbumUserRole;
|
||||
|
||||
class DriftSyncStreamRepository extends DriftDatabaseRepository
|
||||
implements ISyncStreamRepository {
|
||||
@ -161,6 +168,135 @@ class DriftSyncStreamRepository extends DriftDatabaseRepository
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAlbumsV1(Iterable<SyncAlbumV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final album in data) {
|
||||
final companion = RemoteAlbumEntityCompanion(
|
||||
name: Value(album.name),
|
||||
description: Value(album.description),
|
||||
ownerId: Value(album.ownerId),
|
||||
thumbnailAssetId: Value(album.thumbnailAssetId),
|
||||
createdAt: Value(album.createdAt),
|
||||
updatedAt: Value(album.updatedAt),
|
||||
isActivityEnabled: Value(album.isActivityEnabled),
|
||||
order: Value(album.order.toAssetOrder()),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.remoteAlbumEntity,
|
||||
companion.copyWith(id: Value(album.id)),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updateAlbumsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteAlbumsV1(Iterable<SyncAlbumDeleteV1> data) async {
|
||||
try {
|
||||
_db.batch((batch) {
|
||||
for (final album in data) {
|
||||
batch.delete(
|
||||
_db.remoteAlbumEntity,
|
||||
RemoteAlbumEntityCompanion(id: Value(album.albumId)),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing deleteAlbumsV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// Future<void> updateAlbumAssetsV1(Iterable<SyncAlbumAssetV1> data) async {
|
||||
// try {
|
||||
// await _db.remoteAlbumAssetEntity.insertAll(
|
||||
// data.map(
|
||||
// (albumAsset) => RemoteAlbumAssetEntityCompanion.insert(
|
||||
// albumId: albumAsset.albumId,
|
||||
// assetId: albumAsset.assetId,
|
||||
// ),
|
||||
// ),
|
||||
// mode: InsertMode.insertOrIgnore,
|
||||
// );
|
||||
// } catch (e, s) {
|
||||
// _logger.severe('Error while processing updateAlbumAssetsV1', e, s);
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Future<void> deleteAlbumAssetsV1(Iterable<SyncAlbumAssetDeleteV1> data) async {
|
||||
// try {
|
||||
// await _db.batch((batch) {
|
||||
// for (final albumAsset in data) {
|
||||
// batch.delete(
|
||||
// _db.remoteAlbumAssetEntity,
|
||||
// RemoteAlbumAssetEntityCompanion(
|
||||
// albumId: Value(albumAsset.albumId),
|
||||
// assetId: Value(albumAsset.assetId),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
// } catch (e, s) {
|
||||
// _logger.severe('Error while processing deleteAlbumAssetsV1', e, s);
|
||||
// rethrow;
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
Future<void> updateAlbumUsersV1(Iterable<SyncAlbumUserV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final albumUser in data) {
|
||||
final companion = AlbumUserEntityCompanion(
|
||||
role: Value(albumUser.role.toAlbumUserRole()),
|
||||
);
|
||||
|
||||
batch.insert(
|
||||
_db.albumUserEntity,
|
||||
companion.copyWith(
|
||||
albumId: Value(albumUser.albumId),
|
||||
userId: Value(albumUser.userId),
|
||||
),
|
||||
onConflict: DoUpdate((_) => companion),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing updateAlbumUsersV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteAlbumUsersV1(Iterable<SyncAlbumUserDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
for (final albumUser in data) {
|
||||
batch.delete(
|
||||
_db.albumUserEntity,
|
||||
AlbumUserEntityCompanion(
|
||||
albumId: Value(albumUser.albumId),
|
||||
userId: Value(albumUser.userId),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e, s) {
|
||||
_logger.severe('Error while processing deleteAlbumUsersV1', e, s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateAssetsV1(Iterable<SyncAssetV1> data) =>
|
||||
_db.batch((batch) {
|
||||
for (final asset in data) {
|
||||
@ -251,3 +387,19 @@ extension on api.AssetVisibility {
|
||||
_ => throw Exception('Unknown AssetVisibility value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on api.AssetOrder {
|
||||
AssetOrder toAssetOrder() => switch (this) {
|
||||
api.AssetOrder.asc => AssetOrder.asc,
|
||||
api.AssetOrder.desc => AssetOrder.desc,
|
||||
_ => throw Exception('Unknown AssetOrder value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
extension on api.AlbumUserRole {
|
||||
AlbumUserRole toAlbumUserRole() => switch (this) {
|
||||
api.AlbumUserRole.editor => AlbumUserRole.editor,
|
||||
api.AlbumUserRole.viewer => AlbumUserRole.viewer,
|
||||
_ => throw Exception('Unknown AlbumUserRole value: $this'),
|
||||
};
|
||||
}
|
||||
|
@ -6,5 +6,7 @@ mixin AssetEntityMixin on Table {
|
||||
IntColumn get type => intEnum<AssetType>()();
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||
IntColumn get width => integer().nullable()();
|
||||
IntColumn get height => integer().nullable()();
|
||||
IntColumn get durationInSeconds => integer().nullable()();
|
||||
}
|
||||
|
@ -21,4 +21,6 @@ abstract interface class IAssetApiRepository {
|
||||
List<String> list,
|
||||
AssetVisibilityEnum visibility,
|
||||
);
|
||||
|
||||
Future<String?> getAssetMIMEType(String id);
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
||||
|
||||
abstract interface class ICastDestinationService {
|
||||
Future<bool> initialize();
|
||||
CastDestinationType getType();
|
||||
|
||||
void Function(bool)? onConnectionState;
|
||||
|
||||
void Function(Duration)? onCurrentTime;
|
||||
void Function(Duration)? onDuration;
|
||||
|
||||
void Function(String)? onReceiverName;
|
||||
void Function(CastState)? onCastState;
|
||||
|
||||
Future<void> connect(dynamic device);
|
||||
|
||||
void loadMedia(Asset asset, bool reload);
|
||||
|
||||
void play();
|
||||
void pause();
|
||||
void seekTo(Duration position);
|
||||
void stop();
|
||||
Future<void> disconnect();
|
||||
|
||||
Future<List<(String, CastDestinationType, dynamic)>> getDevices();
|
||||
}
|
9
mobile/lib/interfaces/sessions_api.interface.dart
Normal file
9
mobile/lib/interfaces/sessions_api.interface.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:immich_mobile/models/sessions/session_create_response.model.dart';
|
||||
|
||||
abstract interface class ISessionAPIRepository {
|
||||
Future<SessionCreateResponse> createSession(
|
||||
String deviceName,
|
||||
String deviceOS, {
|
||||
int? duration,
|
||||
});
|
||||
}
|
@ -205,34 +205,30 @@ class ImmichAppState extends ConsumerState<ImmichApp>
|
||||
overrides: [
|
||||
localeProvider.overrideWithValue(context.locale),
|
||||
],
|
||||
child: MaterialApp(
|
||||
child: MaterialApp.router(
|
||||
title: 'Immich',
|
||||
debugShowCheckedModeBanner: true,
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: context.locale,
|
||||
debugShowCheckedModeBanner: true,
|
||||
home: MaterialApp.router(
|
||||
title: 'Immich',
|
||||
debugShowCheckedModeBanner: false,
|
||||
themeMode: ref.watch(immichThemeModeProvider),
|
||||
darkTheme: getThemeData(
|
||||
colorScheme: immichTheme.dark,
|
||||
locale: context.locale,
|
||||
),
|
||||
theme: getThemeData(
|
||||
colorScheme: immichTheme.light,
|
||||
locale: context.locale,
|
||||
),
|
||||
routeInformationParser: router.defaultRouteParser(),
|
||||
routerDelegate: router.delegate(
|
||||
navigatorObservers: () => [AppNavigationObserver(ref: ref)],
|
||||
),
|
||||
themeMode: ref.watch(immichThemeModeProvider),
|
||||
darkTheme: getThemeData(
|
||||
colorScheme: immichTheme.dark,
|
||||
locale: context.locale,
|
||||
),
|
||||
theme: getThemeData(
|
||||
colorScheme: immichTheme.light,
|
||||
locale: context.locale,
|
||||
),
|
||||
routeInformationParser: router.defaultRouteParser(),
|
||||
routerDelegate: router.delegate(
|
||||
navigatorObservers: () => [AppNavigationObserver(ref: ref)],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: prefer-single-widget-per-file
|
||||
class MainWidget extends StatelessWidget {
|
||||
const MainWidget({super.key});
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
|
||||
class AvailableAlbum {
|
||||
@ -16,7 +14,6 @@ class AvailableAlbum {
|
||||
Album? album,
|
||||
int? assetCount,
|
||||
DateTime? lastBackup,
|
||||
Uint8List? thumbnailData,
|
||||
}) {
|
||||
return AvailableAlbum(
|
||||
album: album ?? this.album,
|
||||
|
88
mobile/lib/models/cast/cast_manager_state.dart
Normal file
88
mobile/lib/models/cast/cast_manager_state.dart
Normal file
@ -0,0 +1,88 @@
|
||||
import 'dart:convert';
|
||||
|
||||
enum CastDestinationType { googleCast }
|
||||
|
||||
enum CastState { idle, playing, paused, buffering }
|
||||
|
||||
class CastManagerState {
|
||||
final bool isCasting;
|
||||
final String receiverName;
|
||||
final CastState castState;
|
||||
final Duration currentTime;
|
||||
final Duration duration;
|
||||
|
||||
const CastManagerState({
|
||||
required this.isCasting,
|
||||
required this.receiverName,
|
||||
required this.castState,
|
||||
required this.currentTime,
|
||||
required this.duration,
|
||||
});
|
||||
|
||||
CastManagerState copyWith({
|
||||
bool? isCasting,
|
||||
String? receiverName,
|
||||
CastState? castState,
|
||||
Duration? currentTime,
|
||||
Duration? duration,
|
||||
}) {
|
||||
return CastManagerState(
|
||||
isCasting: isCasting ?? this.isCasting,
|
||||
receiverName: receiverName ?? this.receiverName,
|
||||
castState: castState ?? this.castState,
|
||||
currentTime: currentTime ?? this.currentTime,
|
||||
duration: duration ?? this.duration,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
final result = <String, dynamic>{};
|
||||
|
||||
result.addAll({'isCasting': isCasting});
|
||||
result.addAll({'receiverName': receiverName});
|
||||
result.addAll({'castState': castState});
|
||||
result.addAll({'currentTime': currentTime.inSeconds});
|
||||
result.addAll({'duration': duration.inSeconds});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
factory CastManagerState.fromMap(Map<String, dynamic> map) {
|
||||
return CastManagerState(
|
||||
isCasting: map['isCasting'] ?? false,
|
||||
receiverName: map['receiverName'] ?? '',
|
||||
castState: map['castState'] ?? CastState.idle,
|
||||
currentTime: Duration(seconds: map['currentTime']?.toInt() ?? 0),
|
||||
duration: Duration(seconds: map['duration']?.toInt() ?? 0),
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory CastManagerState.fromJson(String source) =>
|
||||
CastManagerState.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'CastManagerState(isCasting: $isCasting, receiverName: $receiverName, castState: $castState, currentTime: $currentTime, duration: $duration)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is CastManagerState &&
|
||||
other.isCasting == isCasting &&
|
||||
other.receiverName == receiverName &&
|
||||
other.castState == castState &&
|
||||
other.currentTime == currentTime &&
|
||||
other.duration == duration;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
isCasting.hashCode ^
|
||||
receiverName.hashCode ^
|
||||
castState.hashCode ^
|
||||
currentTime.hashCode ^
|
||||
duration.hashCode;
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: add-copy-with
|
||||
|
||||
sealed class MapEvent {
|
||||
const MapEvent();
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
class SessionCreateResponse {
|
||||
final String createdAt;
|
||||
final bool current;
|
||||
final String deviceOS;
|
||||
final String deviceType;
|
||||
final String? expiresAt;
|
||||
final String id;
|
||||
final String token;
|
||||
final String updatedAt;
|
||||
|
||||
const SessionCreateResponse({
|
||||
required this.createdAt,
|
||||
required this.current,
|
||||
required this.deviceOS,
|
||||
required this.deviceType,
|
||||
this.expiresAt,
|
||||
required this.id,
|
||||
required this.token,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SessionCreateResponse[createdAt=$createdAt, current=$current, deviceOS=$deviceOS, deviceType=$deviceType, expiresAt=$expiresAt, id=$id, token=$token, updatedAt=$updatedAt]';
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import 'dart:math';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||
@ -20,6 +21,7 @@ import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart
|
||||
import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||
import 'package:immich_mobile/providers/cast.provider.dart';
|
||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
||||
@ -62,6 +64,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
final currentIndex = useValueNotifier(initialIndex);
|
||||
final loadAsset = renderList.loadAsset;
|
||||
final isPlayingMotionVideo = ref.watch(isPlayingMotionVideoProvider);
|
||||
final isCasting = ref.watch(castProvider.select((c) => c.isCasting));
|
||||
|
||||
final videoPlayerKeys = useRef<Map<int, GlobalKey>>({});
|
||||
|
||||
@ -118,6 +121,36 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
const [],
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
final asset = loadAsset(currentIndex.value);
|
||||
|
||||
if (asset.isRemote) {
|
||||
ref.read(castProvider.notifier).loadMedia(asset, false);
|
||||
} else {
|
||||
if (isCasting) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted) {
|
||||
ref.read(castProvider.notifier).stop();
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
duration: const Duration(seconds: 1),
|
||||
content: Text(
|
||||
"local_asset_cast_failed".tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, [
|
||||
ref.watch(castProvider).isCasting,
|
||||
]);
|
||||
|
||||
void showInfo() {
|
||||
final asset = ref.read(currentAssetProvider);
|
||||
if (asset == null) {
|
||||
@ -203,7 +236,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
});
|
||||
});
|
||||
|
||||
PhotoViewGalleryPageOptions buildImage(BuildContext context, Asset asset) {
|
||||
PhotoViewGalleryPageOptions buildImage(Asset asset) {
|
||||
return PhotoViewGalleryPageOptions(
|
||||
onDragStart: (_, details, __) {
|
||||
localPosition.value = details.localPosition;
|
||||
@ -279,7 +312,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
if (newAsset.isImage && !isPlayingMotionVideo) {
|
||||
return buildImage(context, newAsset);
|
||||
return buildImage(newAsset);
|
||||
}
|
||||
return buildVideo(context, newAsset);
|
||||
}
|
||||
@ -356,6 +389,30 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
Timer(const Duration(milliseconds: 400), () {
|
||||
precacheNextImage(next);
|
||||
});
|
||||
|
||||
context.scaffoldMessenger.hideCurrentSnackBar();
|
||||
|
||||
// send image to casting if the server has it
|
||||
if (newAsset.isRemote) {
|
||||
ref.read(castProvider.notifier).loadMedia(newAsset, false);
|
||||
} else {
|
||||
context.scaffoldMessenger.clearSnackBars();
|
||||
|
||||
if (isCasting) {
|
||||
ref.read(castProvider.notifier).stop();
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
duration: const Duration(seconds: 2),
|
||||
content: Text(
|
||||
"local_asset_cast_failed".tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
builder: buildAsset,
|
||||
),
|
||||
|
@ -13,6 +13,7 @@ import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart
|
||||
import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
|
||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||
import 'package:immich_mobile/providers/cast.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
import 'package:immich_mobile/services/asset.service.dart';
|
||||
@ -60,6 +61,8 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
||||
|
||||
final log = Logger('NativeVideoViewerPage');
|
||||
|
||||
final isCasting = ref.watch(castProvider.select((c) => c.isCasting));
|
||||
|
||||
Future<VideoSource?> createSource() async {
|
||||
if (!context.mounted) {
|
||||
return null;
|
||||
@ -391,7 +394,7 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
||||
// This remains under the video to avoid flickering
|
||||
// For motion videos, this is the image portion of the asset
|
||||
Center(key: ValueKey(asset.id), child: image),
|
||||
if (aspectRatio.value != null)
|
||||
if (aspectRatio.value != null && !isCasting)
|
||||
Visibility.maintain(
|
||||
key: ValueKey(asset),
|
||||
visible: isVisible.value,
|
||||
|
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/generated/intl_keys.g.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/partner.provider.dart';
|
||||
import 'package:immich_mobile/providers/search/people.provider.dart';
|
||||
@ -41,13 +42,13 @@ class LibraryPage extends ConsumerWidget {
|
||||
ActionButton(
|
||||
onPressed: () => context.pushRoute(const FavoritesRoute()),
|
||||
icon: Icons.favorite_outline_rounded,
|
||||
label: 'favorites'.tr(),
|
||||
label: IntlKeys.favorites.tr(),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ActionButton(
|
||||
onPressed: () => context.pushRoute(const ArchiveRoute()),
|
||||
icon: Icons.archive_outlined,
|
||||
label: 'archived'.tr(),
|
||||
label: IntlKeys.archived.tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -58,14 +59,14 @@ class LibraryPage extends ConsumerWidget {
|
||||
ActionButton(
|
||||
onPressed: () => context.pushRoute(const SharedLinkRoute()),
|
||||
icon: Icons.link_outlined,
|
||||
label: 'shared_links'.tr(),
|
||||
label: IntlKeys.shared_links.tr(),
|
||||
),
|
||||
SizedBox(width: trashEnabled ? 8 : 0),
|
||||
trashEnabled
|
||||
? ActionButton(
|
||||
onPressed: () => context.pushRoute(const TrashRoute()),
|
||||
icon: Icons.delete_outline_rounded,
|
||||
label: 'trash'.tr(),
|
||||
label: IntlKeys.trash.tr(),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
],
|
||||
@ -133,7 +134,7 @@ class QuickAccessButtons extends ConsumerWidget {
|
||||
size: 26,
|
||||
),
|
||||
title: Text(
|
||||
'folders'.tr(),
|
||||
IntlKeys.folders.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@ -146,7 +147,7 @@ class QuickAccessButtons extends ConsumerWidget {
|
||||
size: 26,
|
||||
),
|
||||
title: Text(
|
||||
'locked_folder'.tr(),
|
||||
IntlKeys.locked_folder.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@ -159,7 +160,7 @@ class QuickAccessButtons extends ConsumerWidget {
|
||||
size: 26,
|
||||
),
|
||||
title: Text(
|
||||
'partners'.tr(),
|
||||
IntlKeys.partners.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@ -275,7 +276,7 @@ class PeopleCollectionCard extends ConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'people'.tr(),
|
||||
IntlKeys.people.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -343,7 +344,7 @@ class LocalAlbumsCollectionCard extends HookConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'on_this_device'.tr(),
|
||||
IntlKeys.on_this_device.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -404,7 +405,7 @@ class PlacesCollectionCard extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'places'.tr(),
|
||||
IntlKeys.places.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
@ -27,6 +27,7 @@ class PeopleCollectionPage extends HookConsumerWidget {
|
||||
) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) {
|
||||
return PersonNameEditForm(personId: personId, personName: personName);
|
||||
},
|
||||
@ -60,80 +61,84 @@ class PeopleCollectionPage extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
body: people.when(
|
||||
data: (people) {
|
||||
if (search.value != null) {
|
||||
people = people.where((person) {
|
||||
return person.name
|
||||
.toLowerCase()
|
||||
.contains(search.value!.toLowerCase());
|
||||
}).toList();
|
||||
}
|
||||
return GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isTablet ? 6 : 3,
|
||||
childAspectRatio: 0.85,
|
||||
mainAxisSpacing: isPortrait && isTablet ? 36 : 0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
itemCount: people.length,
|
||||
itemBuilder: (context, index) {
|
||||
final person = people[index];
|
||||
body: SafeArea(
|
||||
child: people.when(
|
||||
data: (people) {
|
||||
if (search.value != null) {
|
||||
people = people.where((person) {
|
||||
return person.name
|
||||
.toLowerCase()
|
||||
.contains(search.value!.toLowerCase());
|
||||
}).toList();
|
||||
}
|
||||
return GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isTablet ? 6 : 3,
|
||||
childAspectRatio: 0.85,
|
||||
mainAxisSpacing: isPortrait && isTablet ? 36 : 0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
itemCount: people.length,
|
||||
itemBuilder: (context, index) {
|
||||
final person = people[index];
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.pushRoute(
|
||||
PersonResultRoute(
|
||||
personId: person.id,
|
||||
personName: person.name,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Material(
|
||||
shape: const CircleBorder(side: BorderSide.none),
|
||||
elevation: 3,
|
||||
child: CircleAvatar(
|
||||
maxRadius: isTablet ? 120 / 2 : 96 / 2,
|
||||
backgroundImage: NetworkImage(
|
||||
getFaceThumbnailUrl(person.id),
|
||||
headers: headers,
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.pushRoute(
|
||||
PersonResultRoute(
|
||||
personId: person.id,
|
||||
personName: person.name,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Material(
|
||||
shape: const CircleBorder(side: BorderSide.none),
|
||||
elevation: 3,
|
||||
child: CircleAvatar(
|
||||
maxRadius: isTablet ? 120 / 2 : 96 / 2,
|
||||
backgroundImage: NetworkImage(
|
||||
getFaceThumbnailUrl(person.id),
|
||||
headers: headers,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () => showNameEditModel(person.id, person.name),
|
||||
child: person.name.isEmpty
|
||||
? Text(
|
||||
'add_a_name'.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: context.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
),
|
||||
child: Text(
|
||||
person.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
const SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () =>
|
||||
showNameEditModel(person.id, person.name),
|
||||
child: person.name.isEmpty
|
||||
? Text(
|
||||
'add_a_name'.tr(),
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: context.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
),
|
||||
child: Text(
|
||||
person.name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style:
|
||||
context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
error: (error, stack) => const Text("error"),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
error: (error, stack) => const Text("error"),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -28,6 +28,7 @@ class PersonResultPage extends HookConsumerWidget {
|
||||
showEditNameDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) {
|
||||
return PersonNameEditForm(
|
||||
personId: personId,
|
||||
|
12
mobile/lib/platform/native_sync_api.g.dart
generated
12
mobile/lib/platform/native_sync_api.g.dart
generated
@ -37,6 +37,8 @@ class PlatformAsset {
|
||||
required this.type,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.width,
|
||||
this.height,
|
||||
required this.durationInSeconds,
|
||||
});
|
||||
|
||||
@ -50,6 +52,10 @@ class PlatformAsset {
|
||||
|
||||
int? updatedAt;
|
||||
|
||||
int? width;
|
||||
|
||||
int? height;
|
||||
|
||||
int durationInSeconds;
|
||||
|
||||
List<Object?> _toList() {
|
||||
@ -59,6 +65,8 @@ class PlatformAsset {
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
width,
|
||||
height,
|
||||
durationInSeconds,
|
||||
];
|
||||
}
|
||||
@ -75,7 +83,9 @@ class PlatformAsset {
|
||||
type: result[2]! as int,
|
||||
createdAt: result[3] as int?,
|
||||
updatedAt: result[4] as int?,
|
||||
durationInSeconds: result[5]! as int,
|
||||
width: result[5] as int?,
|
||||
height: result[6] as int?,
|
||||
durationInSeconds: result[7]! as int,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: avoid-local-functions
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
@ -63,8 +61,10 @@ final _features = [
|
||||
icon: Icons.delete_sweep_rounded,
|
||||
onTap: (_, ref) async {
|
||||
final db = ref.read(driftProvider);
|
||||
await db.remoteAssetEntity.deleteAll();
|
||||
await db.remoteExifEntity.deleteAll();
|
||||
await db.remoteAssetEntity.deleteAll();
|
||||
await db.remoteAlbumEntity.deleteAll();
|
||||
await db.remoteAlbumAssetEntity.deleteAll();
|
||||
},
|
||||
),
|
||||
_Feature(
|
||||
@ -142,7 +142,6 @@ class _Feature {
|
||||
final Future<void> Function(BuildContext, WidgetRef _) onTap;
|
||||
}
|
||||
|
||||
// ignore: prefer-single-widget-per-file
|
||||
class _DevLogs extends StatelessWidget {
|
||||
const _DevLogs();
|
||||
|
||||
@ -170,7 +169,6 @@ class _DevLogs extends StatelessWidget {
|
||||
builder: (_, logMessages) {
|
||||
return ListView.separated(
|
||||
itemBuilder: (ctx, index) {
|
||||
// ignore: avoid-unsafe-collection-methods
|
||||
final logMessage = logMessages.data![index];
|
||||
return ListTile(
|
||||
title: Text(
|
||||
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: prefer-single-widget-per-file
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -132,6 +130,10 @@ final _remoteStats = [
|
||||
name: 'Exif Entities',
|
||||
load: (db) => db.managers.remoteExifEntity.count(),
|
||||
),
|
||||
_Stat(
|
||||
name: 'Remote Albums',
|
||||
load: (db) => db.managers.remoteAlbumEntity.count(),
|
||||
),
|
||||
];
|
||||
|
||||
@RoutePage()
|
||||
|
@ -5,4 +5,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'api.provider.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
ApiService apiService(Ref ref) => ApiService();
|
||||
ApiService apiService(Ref _) => ApiService();
|
||||
|
2
mobile/lib/providers/api.provider.g.dart
generated
2
mobile/lib/providers/api.provider.g.dart
generated
@ -6,7 +6,7 @@ part of 'api.provider.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$apiServiceHash() => r'93a7e3b4d3004741abc3061c4688239c3a72f9c4';
|
||||
String _$apiServiceHash() => r'187a7de59b064fab1104c23717f18ce0ae3e426c';
|
||||
|
||||
/// See also [apiService].
|
||||
@ProviderFor(apiService)
|
||||
|
@ -5,4 +5,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'app_settings.provider.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
AppSettingsService appSettingsService(Ref ref) => AppSettingsService();
|
||||
AppSettingsService appSettingsService(Ref _) => AppSettingsService();
|
||||
|
@ -7,7 +7,7 @@ part of 'app_settings.provider.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$appSettingsServiceHash() =>
|
||||
r'3736e0d384ec7b1f896938589656dd6eb1552d60';
|
||||
r'2aa16d76a8df869c39486325efc1d08b2d2c284c';
|
||||
|
||||
/// See also [appSettingsService].
|
||||
@ProviderFor(appSettingsService)
|
||||
|
@ -39,6 +39,6 @@ final assetStackStateProvider = StateNotifierProvider.autoDispose
|
||||
);
|
||||
|
||||
@riverpod
|
||||
int assetStackIndex(Ref ref, Asset asset) {
|
||||
int assetStackIndex(Ref _) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -6,155 +6,22 @@ part of 'asset_stack.provider.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$assetStackIndexHash() => r'38b4b0116e3e4592620b118ae01cf89b77da9cfe';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
String _$assetStackIndexHash() => r'086ddb782e3eb38b80d755666fe35be8fe7322d7';
|
||||
|
||||
/// See also [assetStackIndex].
|
||||
@ProviderFor(assetStackIndex)
|
||||
const assetStackIndexProvider = AssetStackIndexFamily();
|
||||
|
||||
/// See also [assetStackIndex].
|
||||
class AssetStackIndexFamily extends Family<int> {
|
||||
/// See also [assetStackIndex].
|
||||
const AssetStackIndexFamily();
|
||||
|
||||
/// See also [assetStackIndex].
|
||||
AssetStackIndexProvider call(
|
||||
Asset asset,
|
||||
) {
|
||||
return AssetStackIndexProvider(
|
||||
asset,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AssetStackIndexProvider getProviderOverride(
|
||||
covariant AssetStackIndexProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.asset,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'assetStackIndexProvider';
|
||||
}
|
||||
|
||||
/// See also [assetStackIndex].
|
||||
class AssetStackIndexProvider extends AutoDisposeProvider<int> {
|
||||
/// See also [assetStackIndex].
|
||||
AssetStackIndexProvider(
|
||||
Asset asset,
|
||||
) : this._internal(
|
||||
(ref) => assetStackIndex(
|
||||
ref as AssetStackIndexRef,
|
||||
asset,
|
||||
),
|
||||
from: assetStackIndexProvider,
|
||||
name: r'assetStackIndexProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$assetStackIndexHash,
|
||||
dependencies: AssetStackIndexFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
AssetStackIndexFamily._allTransitiveDependencies,
|
||||
asset: asset,
|
||||
);
|
||||
|
||||
AssetStackIndexProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.asset,
|
||||
}) : super.internal();
|
||||
|
||||
final Asset asset;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
int Function(AssetStackIndexRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: AssetStackIndexProvider._internal(
|
||||
(ref) => create(ref as AssetStackIndexRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
asset: asset,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeProviderElement<int> createElement() {
|
||||
return _AssetStackIndexProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is AssetStackIndexProvider && other.asset == asset;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, asset.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
final assetStackIndexProvider = AutoDisposeProvider<int>.internal(
|
||||
assetStackIndex,
|
||||
name: r'assetStackIndexProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$assetStackIndexHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin AssetStackIndexRef on AutoDisposeProviderRef<int> {
|
||||
/// The parameter `asset` of this provider.
|
||||
Asset get asset;
|
||||
}
|
||||
|
||||
class _AssetStackIndexProviderElement extends AutoDisposeProviderElement<int>
|
||||
with AssetStackIndexRef {
|
||||
_AssetStackIndexProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Asset get asset => (origin as AssetStackIndexProvider).asset;
|
||||
}
|
||||
typedef AssetStackIndexRef = AutoDisposeProviderRef<int>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
@ -144,7 +144,7 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
return await _downloadService.downloadAll(assets);
|
||||
}
|
||||
|
||||
void downloadAsset(Asset asset, BuildContext context) async {
|
||||
void downloadAsset(Asset asset) async {
|
||||
await _downloadService.download(asset);
|
||||
}
|
||||
|
||||
@ -186,6 +186,7 @@ class DownloadStateNotifier extends StateNotifier<DownloadState> {
|
||||
return const ShareDialog();
|
||||
},
|
||||
barrierDismissible: false,
|
||||
useRootNavigator: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
93
mobile/lib/providers/cast.provider.dart
Normal file
93
mobile/lib/providers/cast.provider.dart
Normal file
@ -0,0 +1,93 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/cast_destination_service.interface.dart';
|
||||
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
||||
import 'package:immich_mobile/services/gcast.service.dart';
|
||||
|
||||
final castProvider = StateNotifierProvider<CastNotifier, CastManagerState>(
|
||||
(ref) => CastNotifier(ref.watch(gCastServiceProvider)),
|
||||
);
|
||||
|
||||
class CastNotifier extends StateNotifier<CastManagerState> {
|
||||
// more cast providers can be added here (ie Fcast)
|
||||
final ICastDestinationService _gCastService;
|
||||
|
||||
List<(String, CastDestinationType, dynamic)> discovered = List.empty();
|
||||
|
||||
CastNotifier(this._gCastService)
|
||||
: super(
|
||||
const CastManagerState(
|
||||
isCasting: false,
|
||||
currentTime: Duration.zero,
|
||||
duration: Duration.zero,
|
||||
receiverName: '',
|
||||
castState: CastState.idle,
|
||||
),
|
||||
) {
|
||||
_gCastService.onConnectionState = _onConnectionState;
|
||||
_gCastService.onCurrentTime = _onCurrentTime;
|
||||
_gCastService.onDuration = _onDuration;
|
||||
_gCastService.onReceiverName = _onReceiverName;
|
||||
_gCastService.onCastState = _onCastState;
|
||||
}
|
||||
|
||||
void _onConnectionState(bool isCasting) {
|
||||
state = state.copyWith(isCasting: isCasting);
|
||||
}
|
||||
|
||||
void _onCurrentTime(Duration currentTime) {
|
||||
state = state.copyWith(currentTime: currentTime);
|
||||
}
|
||||
|
||||
void _onDuration(Duration duration) {
|
||||
state = state.copyWith(duration: duration);
|
||||
}
|
||||
|
||||
void _onReceiverName(String receiverName) {
|
||||
state = state.copyWith(receiverName: receiverName);
|
||||
}
|
||||
|
||||
void _onCastState(CastState castState) {
|
||||
state = state.copyWith(castState: castState);
|
||||
}
|
||||
|
||||
void loadMedia(Asset asset, bool reload) {
|
||||
_gCastService.loadMedia(asset, reload);
|
||||
}
|
||||
|
||||
Future<void> connect(CastDestinationType type, dynamic device) async {
|
||||
switch (type) {
|
||||
case CastDestinationType.googleCast:
|
||||
await _gCastService.connect(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<(String, CastDestinationType, dynamic)>> getDevices() async {
|
||||
if (discovered.isEmpty) {
|
||||
discovered = await _gCastService.getDevices();
|
||||
}
|
||||
|
||||
return discovered;
|
||||
}
|
||||
|
||||
void play() {
|
||||
_gCastService.play();
|
||||
}
|
||||
|
||||
void pause() {
|
||||
_gCastService.pause();
|
||||
}
|
||||
|
||||
void seekTo(Duration position) {
|
||||
_gCastService.seekTo(position);
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_gCastService.stop();
|
||||
}
|
||||
|
||||
Future<void> disconnect() async {
|
||||
await _gCastService.disconnect();
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'immich_logo_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<Uint8List> immichLogo(Ref ref) async {
|
||||
Future<Uint8List> immichLogo(Ref _) async {
|
||||
final json = await rootBundle.loadString('assets/immich-logo.json');
|
||||
final j = jsonDecode(json);
|
||||
return base64Decode(j['content']);
|
||||
|
2
mobile/lib/providers/immich_logo_provider.g.dart
generated
2
mobile/lib/providers/immich_logo_provider.g.dart
generated
@ -6,7 +6,7 @@ part of 'immich_logo_provider.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$immichLogoHash() => r'6f23d217c44279537b7edee1ca80ebf47f69a4d0';
|
||||
String _$immichLogoHash() => r'6de7fcca1ef9acef6ab7398eb0c664080747e0ea';
|
||||
|
||||
/// See also [immichLogo].
|
||||
@ProviderFor(immichLogo)
|
||||
|
@ -72,4 +72,12 @@ class AssetApiRepository extends ApiRepository implements IAssetApiRepository {
|
||||
return AssetVisibility.archive;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getAssetMIMEType(String assetId) async {
|
||||
final response = await checkNull(_api.getAssetInfo(assetId));
|
||||
|
||||
// we need to get the MIME of the thumbnail once that gets added to the API
|
||||
return response.originalMimeType;
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,10 @@ class AuthRepository extends DatabaseRepository implements IAuthRepository {
|
||||
db.albums.clear(),
|
||||
db.eTags.clear(),
|
||||
db.users.clear(),
|
||||
_drift.remoteAssetEntity.deleteAll(),
|
||||
_drift.remoteExifEntity.deleteAll(),
|
||||
_drift.remoteAssetEntity.deleteAll(),
|
||||
_drift.remoteAlbumEntity.deleteAll(),
|
||||
_drift.remoteAlbumAssetEntity.deleteAll(),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
75
mobile/lib/repositories/gcast.repository.dart
Normal file
75
mobile/lib/repositories/gcast.repository.dart
Normal file
@ -0,0 +1,75 @@
|
||||
import 'package:cast/device.dart';
|
||||
import 'package:cast/session.dart';
|
||||
import 'package:cast/session_manager.dart';
|
||||
import 'package:cast/discovery_service.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
final gCastRepositoryProvider = Provider((_) {
|
||||
return GCastRepository();
|
||||
});
|
||||
|
||||
class GCastRepository {
|
||||
CastSession? _castSession;
|
||||
|
||||
void Function(CastSessionState)? onCastStatus;
|
||||
void Function(Map<String, dynamic>)? onCastMessage;
|
||||
|
||||
Map<String, dynamic>? _receiverStatus;
|
||||
|
||||
GCastRepository();
|
||||
|
||||
Future<void> connect(CastDevice device) async {
|
||||
_castSession = await CastSessionManager().startSession(device);
|
||||
|
||||
_castSession?.stateStream.listen((state) {
|
||||
onCastStatus?.call(state);
|
||||
});
|
||||
|
||||
_castSession?.messageStream.listen((message) {
|
||||
onCastMessage?.call(message);
|
||||
if (message['type'] == 'RECEIVER_STATUS') {
|
||||
_receiverStatus = message;
|
||||
}
|
||||
});
|
||||
|
||||
// open the default receiver
|
||||
sendMessage(CastSession.kNamespaceReceiver, {
|
||||
'type': 'LAUNCH',
|
||||
'appId': 'CC1AD845',
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> disconnect() async {
|
||||
final sessionID = getSessionId();
|
||||
|
||||
sendMessage(CastSession.kNamespaceReceiver, {
|
||||
'type': "STOP",
|
||||
"sessionId": sessionID,
|
||||
});
|
||||
|
||||
// wait 500ms to ensure the stop command is processed
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
await _castSession?.close();
|
||||
}
|
||||
|
||||
String? getSessionId() {
|
||||
if (_receiverStatus == null) {
|
||||
return null;
|
||||
}
|
||||
return _receiverStatus!['status']['applications'][0]['sessionId'];
|
||||
}
|
||||
|
||||
void sendMessage(String namespace, Map<String, dynamic> message) {
|
||||
if (_castSession == null) {
|
||||
throw Exception("Cast session is not established");
|
||||
}
|
||||
|
||||
_castSession!.sendMessage(namespace, message);
|
||||
}
|
||||
|
||||
Future<List<CastDevice>> listDestinations() async {
|
||||
return await CastDiscoveryService()
|
||||
.search(timeout: const Duration(seconds: 3));
|
||||
}
|
||||
}
|
47
mobile/lib/repositories/sessions_api.repository.dart
Normal file
47
mobile/lib/repositories/sessions_api.repository.dart
Normal file
@ -0,0 +1,47 @@
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/interfaces/sessions_api.interface.dart';
|
||||
import 'package:immich_mobile/models/sessions/session_create_response.model.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/repositories/api.repository.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
final sessionsAPIRepositoryProvider = Provider(
|
||||
(ref) => SessionsAPIRepository(
|
||||
ref.watch(apiServiceProvider).sessionsApi,
|
||||
),
|
||||
);
|
||||
|
||||
class SessionsAPIRepository extends ApiRepository
|
||||
implements ISessionAPIRepository {
|
||||
final SessionsApi _api;
|
||||
|
||||
SessionsAPIRepository(this._api);
|
||||
|
||||
@override
|
||||
Future<SessionCreateResponse> createSession(
|
||||
String deviceType,
|
||||
String deviceOS, {
|
||||
int? duration,
|
||||
}) async {
|
||||
final dto = await checkNull(
|
||||
_api.createSession(
|
||||
SessionCreateDto(
|
||||
deviceType: deviceType,
|
||||
deviceOS: deviceOS,
|
||||
duration: duration,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return SessionCreateResponse(
|
||||
id: dto.id,
|
||||
current: dto.current,
|
||||
deviceType: deviceType,
|
||||
deviceOS: deviceOS,
|
||||
expiresAt: dto.expiresAt,
|
||||
createdAt: dto.createdAt,
|
||||
updatedAt: dto.updatedAt,
|
||||
token: dto.token,
|
||||
);
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ class ApiService implements Authentication {
|
||||
late StacksApi stacksApi;
|
||||
late ViewApi viewApi;
|
||||
late MemoriesApi memoriesApi;
|
||||
late SessionsApi sessionsApi;
|
||||
|
||||
ApiService() {
|
||||
// The below line ensures that the api clients are initialized when the service is instantiated
|
||||
@ -72,6 +73,7 @@ class ApiService implements Authentication {
|
||||
stacksApi = StacksApi(_apiClient);
|
||||
viewApi = ViewApi(_apiClient);
|
||||
memoriesApi = MemoriesApi(_apiClient);
|
||||
sessionsApi = SessionsApi(_apiClient);
|
||||
}
|
||||
|
||||
Future<void> _setUserAgentHeader() async {
|
||||
|
@ -18,7 +18,6 @@ import 'package:immich_mobile/interfaces/backup_album.interface.dart';
|
||||
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||
import 'package:immich_mobile/models/backup/current_upload_asset.model.dart';
|
||||
import 'package:immich_mobile/models/backup/error_upload_asset.model.dart';
|
||||
import 'package:immich_mobile/models/backup/success_upload_asset.model.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
@ -489,7 +488,6 @@ class BackgroundService {
|
||||
_cancellationToken!,
|
||||
pmProgressHandler: pmProgressHandler,
|
||||
onSuccess: (result) => _onAssetUploaded(
|
||||
result: result,
|
||||
shouldNotify: notifyTotalProgress,
|
||||
),
|
||||
onProgress: (bytes, totalBytes) =>
|
||||
@ -511,7 +509,6 @@ class BackgroundService {
|
||||
}
|
||||
|
||||
void _onAssetUploaded({
|
||||
required SuccessUploadAsset result,
|
||||
bool shouldNotify = false,
|
||||
}) async {
|
||||
if (!shouldNotify) {
|
||||
|
@ -184,10 +184,10 @@ class BackupVerificationService {
|
||||
// for images: make sure they are pixel-wise identical
|
||||
// (skip first few KBs containing metadata)
|
||||
final Uint64List localImage =
|
||||
_fakeDecodeImg(local, await file.readAsBytes());
|
||||
_fakeDecodeImg(await file.readAsBytes());
|
||||
final res = await apiService.assetsApi
|
||||
.downloadAssetWithHttpInfo(remote.remoteId!);
|
||||
final Uint64List remoteImage = _fakeDecodeImg(remote, res.bodyBytes);
|
||||
final Uint64List remoteImage = _fakeDecodeImg(res.bodyBytes);
|
||||
|
||||
final eq = const ListEquality().equals(remoteImage, localImage);
|
||||
return eq;
|
||||
@ -198,7 +198,7 @@ class BackupVerificationService {
|
||||
return false;
|
||||
}
|
||||
|
||||
static Uint64List _fakeDecodeImg(Asset asset, Uint8List bytes) {
|
||||
static Uint64List _fakeDecodeImg(Uint8List bytes) {
|
||||
const headerLength = 131072; // assume header is at most 128 KB
|
||||
final start = bytes.length < headerLength * 2
|
||||
? (bytes.length ~/ (4 * 8)) * 8
|
||||
|
295
mobile/lib/services/gcast.service.dart
Normal file
295
mobile/lib/services/gcast.service.dart
Normal file
@ -0,0 +1,295 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cast/session.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||
import 'package:immich_mobile/interfaces/cast_destination_service.interface.dart';
|
||||
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
||||
import 'package:immich_mobile/models/sessions/session_create_response.model.dart';
|
||||
import 'package:immich_mobile/repositories/asset_api.repository.dart';
|
||||
import 'package:immich_mobile/repositories/gcast.repository.dart';
|
||||
import 'package:immich_mobile/repositories/sessions_api.repository.dart';
|
||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||
// ignore: import_rule_openapi, we are only using the AssetMediaSize enum
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
final gCastServiceProvider = Provider(
|
||||
(ref) => GCastService(
|
||||
ref.watch(gCastRepositoryProvider),
|
||||
ref.watch(sessionsAPIRepositoryProvider),
|
||||
ref.watch(assetApiRepositoryProvider),
|
||||
),
|
||||
);
|
||||
|
||||
class GCastService implements ICastDestinationService {
|
||||
final GCastRepository _gCastRepository;
|
||||
final SessionsAPIRepository _sessionsApiService;
|
||||
final AssetApiRepository _assetApiRepository;
|
||||
|
||||
SessionCreateResponse? sessionKey;
|
||||
String? currentAssetId;
|
||||
bool isConnected = false;
|
||||
int? _sessionId;
|
||||
Timer? _mediaStatusPollingTimer;
|
||||
|
||||
@override
|
||||
void Function(bool)? onConnectionState;
|
||||
@override
|
||||
void Function(Duration)? onCurrentTime;
|
||||
@override
|
||||
void Function(Duration)? onDuration;
|
||||
@override
|
||||
void Function(String)? onReceiverName;
|
||||
@override
|
||||
void Function(CastState)? onCastState;
|
||||
|
||||
GCastService(
|
||||
this._gCastRepository,
|
||||
this._sessionsApiService,
|
||||
this._assetApiRepository,
|
||||
) {
|
||||
_gCastRepository.onCastStatus = _onCastStatusCallback;
|
||||
_gCastRepository.onCastMessage = _onCastMessageCallback;
|
||||
}
|
||||
|
||||
void _onCastStatusCallback(CastSessionState state) {
|
||||
if (state == CastSessionState.connected) {
|
||||
onConnectionState?.call(true);
|
||||
isConnected = true;
|
||||
} else if (state == CastSessionState.closed) {
|
||||
onConnectionState?.call(false);
|
||||
isConnected = false;
|
||||
onReceiverName?.call("");
|
||||
currentAssetId = null;
|
||||
}
|
||||
}
|
||||
|
||||
void _onCastMessageCallback(Map<String, dynamic> message) {
|
||||
switch (message['type']) {
|
||||
case "MEDIA_STATUS":
|
||||
_handleMediaStatus(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _handleMediaStatus(Map<String, dynamic> message) {
|
||||
final statusList =
|
||||
(message['status'] as List).whereType<Map<String, dynamic>>().toList();
|
||||
|
||||
if (statusList.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final status = statusList[0];
|
||||
switch (status['playerState']) {
|
||||
case "PLAYING":
|
||||
onCastState?.call(CastState.playing);
|
||||
break;
|
||||
case "PAUSED":
|
||||
onCastState?.call(CastState.paused);
|
||||
break;
|
||||
case "BUFFERING":
|
||||
onCastState?.call(CastState.buffering);
|
||||
break;
|
||||
case "IDLE":
|
||||
onCastState?.call(CastState.idle);
|
||||
|
||||
// stop polling for media status if the video finished playing
|
||||
if (status["idleReason"] == "FINISHED") {
|
||||
_mediaStatusPollingTimer?.cancel();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (status["media"] != null && status["media"]["duration"] != null) {
|
||||
final duration = Duration(
|
||||
milliseconds: (status["media"]["duration"] * 1000 ?? 0).toInt(),
|
||||
);
|
||||
onDuration?.call(duration);
|
||||
}
|
||||
|
||||
if (status["mediaSessionId"] != null) {
|
||||
_sessionId = status["mediaSessionId"];
|
||||
}
|
||||
|
||||
if (status["currentTime"] != null) {
|
||||
final currentTime =
|
||||
Duration(milliseconds: (status["currentTime"] * 1000 ?? 0).toInt());
|
||||
onCurrentTime?.call(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(dynamic device) async {
|
||||
await _gCastRepository.connect(device);
|
||||
|
||||
onReceiverName?.call(device.extras["fn"] ?? "Google Cast");
|
||||
}
|
||||
|
||||
@override
|
||||
CastDestinationType getType() {
|
||||
return CastDestinationType.googleCast;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> initialize() async {
|
||||
// there is nothing blocking us from using Google Cast that we can check for
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disconnect() async {
|
||||
onReceiverName?.call("");
|
||||
currentAssetId = null;
|
||||
await _gCastRepository.disconnect();
|
||||
}
|
||||
|
||||
bool isSessionValid() {
|
||||
// check if we already have a session token
|
||||
// we should always have a expiration date
|
||||
if (sessionKey == null || sessionKey?.expiresAt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final tokenExpiration = DateTime.parse(sessionKey!.expiresAt!);
|
||||
|
||||
// we want to make sure we have at least 10 seconds remaining in the session
|
||||
// this is to account for network latency and other delays when sending the request
|
||||
final bufferedExpiration =
|
||||
tokenExpiration.subtract(const Duration(seconds: 10));
|
||||
|
||||
return bufferedExpiration.isAfter(DateTime.now());
|
||||
}
|
||||
|
||||
@override
|
||||
void loadMedia(Asset asset, bool reload) async {
|
||||
if (!isConnected) {
|
||||
return;
|
||||
} else if (asset.remoteId == null) {
|
||||
return;
|
||||
} else if (asset.remoteId == currentAssetId && !reload) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create a session key
|
||||
if (!isSessionValid()) {
|
||||
sessionKey = await _sessionsApiService.createSession(
|
||||
"Cast",
|
||||
"Google Cast",
|
||||
duration: const Duration(minutes: 15).inSeconds,
|
||||
);
|
||||
}
|
||||
|
||||
final unauthenticatedUrl = asset.isVideo
|
||||
? getPlaybackUrlForRemoteId(
|
||||
asset.remoteId!,
|
||||
)
|
||||
: getThumbnailUrlForRemoteId(
|
||||
asset.remoteId!,
|
||||
type: AssetMediaSize.fullsize,
|
||||
);
|
||||
|
||||
final authenticatedURL =
|
||||
"$unauthenticatedUrl&sessionKey=${sessionKey?.token}";
|
||||
|
||||
// get image mime type
|
||||
final mimeType =
|
||||
await _assetApiRepository.getAssetMIMEType(asset.remoteId!);
|
||||
|
||||
if (mimeType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "LOAD",
|
||||
"media": {
|
||||
"contentId": authenticatedURL,
|
||||
"streamType": "BUFFERED",
|
||||
"contentType": mimeType,
|
||||
"contentUrl": authenticatedURL,
|
||||
},
|
||||
"autoplay": true,
|
||||
});
|
||||
|
||||
currentAssetId = asset.remoteId;
|
||||
|
||||
// we need to poll for media status since the cast device does not
|
||||
// send a message when the media is loaded for whatever reason
|
||||
// only do this on videos
|
||||
_mediaStatusPollingTimer?.cancel();
|
||||
|
||||
if (asset.isVideo) {
|
||||
_mediaStatusPollingTimer =
|
||||
Timer.periodic(const Duration(milliseconds: 500), (timer) {
|
||||
if (isConnected) {
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "GET_STATUS",
|
||||
"mediaSessionId": _sessionId,
|
||||
});
|
||||
} else {
|
||||
timer.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void play() {
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "PLAY",
|
||||
"mediaSessionId": _sessionId,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void pause() {
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "PAUSE",
|
||||
"mediaSessionId": _sessionId,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void seekTo(Duration position) {
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "SEEK",
|
||||
"mediaSessionId": _sessionId,
|
||||
"currentTime": position.inSeconds,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void stop() {
|
||||
_gCastRepository.sendMessage(CastSession.kNamespaceMedia, {
|
||||
"type": "STOP",
|
||||
"mediaSessionId": _sessionId,
|
||||
});
|
||||
_mediaStatusPollingTimer?.cancel();
|
||||
|
||||
currentAssetId = null;
|
||||
}
|
||||
|
||||
// 0x01 is display capability bitmask
|
||||
bool isDisplay(int ca) => (ca & 0x01) != 0;
|
||||
|
||||
@override
|
||||
Future<List<(String, CastDestinationType, dynamic)>> getDevices() async {
|
||||
final dests = await _gCastRepository.listDestinations();
|
||||
|
||||
return dests
|
||||
.map(
|
||||
(device) => (
|
||||
device.extras["fn"] ?? "Google Cast",
|
||||
CastDestinationType.googleCast,
|
||||
device
|
||||
),
|
||||
)
|
||||
.where((device) {
|
||||
final caString = device.$3.extras["ca"];
|
||||
final caNumber = int.tryParse(caString ?? "0") ?? 0;
|
||||
|
||||
return isDisplay(caNumber);
|
||||
}).toList(growable: false);
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: avoid-unsafe-collection-methods
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
|
@ -73,6 +73,10 @@ String getThumbnailUrlForRemoteId(
|
||||
return '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail?size=${type.value}';
|
||||
}
|
||||
|
||||
String getPlaybackUrlForRemoteId(final String id) {
|
||||
return '${Store.get(StoreKey.serverEndpoint)}/assets/$id/video/playback?';
|
||||
}
|
||||
|
||||
String getFaceThumbnailUrl(final String personId) {
|
||||
return '${Store.get(StoreKey.serverEndpoint)}/people/$personId/thumbnail';
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/cancel.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
@ -58,9 +59,7 @@ Cancelable<T?> runInIsolateGentle<T>({
|
||||
stack,
|
||||
);
|
||||
} finally {
|
||||
// Wait for the logs to flush
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
// Always close the new db connection on Isolate end
|
||||
await LogService.I.flushBuffer();
|
||||
ref.read(driftProvider).close();
|
||||
ref.read(isarProvider).close();
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: avoid-unsafe-collection-methods
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
@ -43,6 +43,7 @@ void handleShareAssets(
|
||||
return const ShareDialog();
|
||||
},
|
||||
barrierDismissible: false,
|
||||
useRootNavigator: false,
|
||||
);
|
||||
}
|
||||
|
||||
@ -93,7 +94,7 @@ Future<void> handleFavoriteAssets(
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: toastMessage,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
gravity: toastGravity,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -163,9 +164,8 @@ Future<void> handleSetAssetsVisibility(
|
||||
WidgetRef ref,
|
||||
BuildContext context,
|
||||
AssetVisibilityEnum visibility,
|
||||
List<Asset> selection, {
|
||||
ToastGravity toastGravity = ToastGravity.BOTTOM,
|
||||
}) async {
|
||||
List<Asset> selection,
|
||||
) async {
|
||||
if (selection.isNotEmpty) {
|
||||
await ref
|
||||
.watch(assetProvider.notifier)
|
||||
|
@ -1,4 +1,3 @@
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// Based on https://stackoverflow.com/a/52625182
|
||||
|
||||
import 'dart:async';
|
||||
@ -164,7 +163,6 @@ class _CustomLongPressGestureRecognizer extends LongPressGestureRecognizer {
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: prefer-single-widget-per-file
|
||||
class AssetIndexWrapper extends SingleChildRenderObjectWidget {
|
||||
final int rowIndex;
|
||||
final int sectionIndex;
|
||||
@ -177,6 +175,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
// ignore: library_private_types_in_public_api
|
||||
_AssetIndexProxy createRenderObject(BuildContext context) {
|
||||
return _AssetIndexProxy(
|
||||
index: AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex),
|
||||
@ -186,6 +185,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget {
|
||||
@override
|
||||
void updateRenderObject(
|
||||
BuildContext context,
|
||||
// ignore: library_private_types_in_public_api
|
||||
_AssetIndexProxy renderObject,
|
||||
) {
|
||||
renderObject.index =
|
||||
|
@ -1,5 +1,3 @@
|
||||
// ignore_for_file: prefer-single-widget-per-file
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
|
@ -80,8 +80,7 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
this.labelTextBuilder,
|
||||
this.labelConstraints,
|
||||
}) : assert(child.scrollDirection == Axis.vertical),
|
||||
scrollThumbBuilder =
|
||||
_thumbRRectBuilder(scrollThumbKey, alwaysVisibleScrollThumb);
|
||||
scrollThumbBuilder = _thumbRRectBuilder(alwaysVisibleScrollThumb);
|
||||
|
||||
DraggableScrollbar.arrows({
|
||||
super.key,
|
||||
@ -97,8 +96,7 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
this.labelTextBuilder,
|
||||
this.labelConstraints,
|
||||
}) : assert(child.scrollDirection == Axis.vertical),
|
||||
scrollThumbBuilder =
|
||||
_thumbArrowBuilder(scrollThumbKey, alwaysVisibleScrollThumb);
|
||||
scrollThumbBuilder = _thumbArrowBuilder(alwaysVisibleScrollThumb);
|
||||
|
||||
DraggableScrollbar.semicircle({
|
||||
super.key,
|
||||
@ -201,7 +199,6 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
}
|
||||
|
||||
static ScrollThumbBuilder _thumbArrowBuilder(
|
||||
Key? scrollThumbKey,
|
||||
bool alwaysVisibleScrollThumb,
|
||||
) {
|
||||
return (
|
||||
@ -239,7 +236,6 @@ class DraggableScrollbar extends StatefulWidget {
|
||||
}
|
||||
|
||||
static ScrollThumbBuilder _thumbRRectBuilder(
|
||||
Key? scrollThumbKey,
|
||||
bool alwaysVisibleScrollThumb,
|
||||
) {
|
||||
return (
|
||||
|
@ -48,7 +48,7 @@ class ThumbnailImage extends ConsumerWidget {
|
||||
// Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id
|
||||
final isFromDto = asset.id == noDbId;
|
||||
|
||||
Widget buildSelectionIcon(Asset asset) {
|
||||
Widget buildSelectionIcon() {
|
||||
if (isSelected) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
@ -233,7 +233,7 @@ class ThumbnailImage extends ConsumerWidget {
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: buildSelectionIcon(asset),
|
||||
child: buildSelectionIcon(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user