Compare commits
1 Commits
fix/folder
...
fix/map-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c7a29b2f4 |
@@ -55,7 +55,7 @@
|
|||||||
"userEnvProbe": "loginInteractiveShell",
|
"userEnvProbe": "loginInteractiveShell",
|
||||||
"remoteEnv": {
|
"remoteEnv": {
|
||||||
// The location where your uploaded files are stored
|
// The location where your uploaded files are stored
|
||||||
"UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION:./library}",
|
"UPLOAD_LOCATION": "${localEnv:UPLOAD_LOCATION:upload-devcontainer-volume}",
|
||||||
// Connection secret for postgres. You should change it to a random password
|
// Connection secret for postgres. You should change it to a random password
|
||||||
// Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
// Please use only the characters `A-Za-z0-9`, without special characters or spaces
|
||||||
"DB_PASSWORD": "${localEnv:DB_PASSWORD:postgres}",
|
"DB_PASSWORD": "${localEnv:DB_PASSWORD:postgres}",
|
||||||
|
|||||||
@@ -51,19 +51,14 @@ fix_permissions() {
|
|||||||
|
|
||||||
run_cmd sudo find "${IMMICH_WORKSPACE}/server/upload" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres/*" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres" -exec chown node {} +
|
run_cmd sudo find "${IMMICH_WORKSPACE}/server/upload" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres/*" -not -path "${IMMICH_WORKSPACE}/server/upload/postgres" -exec chown node {} +
|
||||||
|
|
||||||
# Change ownership for directories that exist
|
run_cmd sudo chown node -R "${IMMICH_WORKSPACE}/.vscode" \
|
||||||
for dir in "${IMMICH_WORKSPACE}/.vscode" \
|
|
||||||
"${IMMICH_WORKSPACE}/cli/node_modules" \
|
"${IMMICH_WORKSPACE}/cli/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/e2e/node_modules" \
|
"${IMMICH_WORKSPACE}/e2e/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/open-api/typescript-sdk/node_modules" \
|
"${IMMICH_WORKSPACE}/open-api/typescript-sdk/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/server/node_modules" \
|
"${IMMICH_WORKSPACE}/server/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/server/dist" \
|
"${IMMICH_WORKSPACE}/server/dist" \
|
||||||
"${IMMICH_WORKSPACE}/web/node_modules" \
|
"${IMMICH_WORKSPACE}/web/node_modules" \
|
||||||
"${IMMICH_WORKSPACE}/web/dist"; do
|
"${IMMICH_WORKSPACE}/web/dist"
|
||||||
if [ -d "$dir" ]; then
|
|
||||||
run_cmd sudo chown node -R "$dir"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
log ""
|
log ""
|
||||||
}
|
}
|
||||||
@@ -73,10 +68,10 @@ install_dependencies() {
|
|||||||
log "Installing dependencies"
|
log "Installing dependencies"
|
||||||
(
|
(
|
||||||
cd "${IMMICH_WORKSPACE}" || exit 1
|
cd "${IMMICH_WORKSPACE}" || exit 1
|
||||||
run_cmd make ci-server
|
run_cmd make install-server
|
||||||
run_cmd make ci-sdk
|
run_cmd make install-sdk
|
||||||
run_cmd make build-sdk
|
run_cmd make build-sdk
|
||||||
run_cmd make ci-web
|
run_cmd make install-web
|
||||||
)
|
)
|
||||||
log ""
|
log ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ services:
|
|||||||
build:
|
build:
|
||||||
target: dev-container-server
|
target: dev-container-server
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
hostname: immich-dev
|
|
||||||
environment:
|
environment:
|
||||||
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
|
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
|
||||||
volumes: !override
|
volumes: !override
|
||||||
@@ -13,8 +12,8 @@ services:
|
|||||||
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
||||||
- server_node_modules:/workspaces/immich/server/node_modules
|
- server_node_modules:/workspaces/immich/server/node_modules
|
||||||
- web_node_modules:/workspaces/immich/web/node_modules
|
- web_node_modules:/workspaces/immich/web/node_modules
|
||||||
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/workspaces/immich/server/upload
|
- ${UPLOAD_LOCATION-./Library}/photos:/workspaces/immich/server/upload
|
||||||
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/workspaces/immich/server/upload/upload
|
- ${UPLOAD_LOCATION-./Library}/photos/upload:/workspaces/immich/server/upload/upload
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|
||||||
immich-web:
|
immich-web:
|
||||||
@@ -30,9 +29,8 @@ services:
|
|||||||
POSTGRES_USER: ${DB_USERNAME-postgres}
|
POSTGRES_USER: ${DB_USERNAME-postgres}
|
||||||
POSTGRES_DB: ${DB_DATABASE_NAME-immich}
|
POSTGRES_DB: ${DB_DATABASE_NAME-immich}
|
||||||
POSTGRES_INITDB_ARGS: '--data-checksums'
|
POSTGRES_INITDB_ARGS: '--data-checksums'
|
||||||
POSTGRES_HOST_AUTH_METHOD: md5
|
volumes:
|
||||||
volumes:
|
- ${UPLOAD_LOCATION-./Library}/postgres:/var/lib/postgresql/data
|
||||||
- ${UPLOAD_LOCATION:-postgres-devcontainer-volume}${UPLOAD_LOCATION:+/postgres}:/var/lib/postgresql/data
|
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
env_file: !reset []
|
env_file: !reset []
|
||||||
@@ -44,6 +42,4 @@ volumes:
|
|||||||
open_api_node_modules:
|
open_api_node_modules:
|
||||||
server_node_modules:
|
server_node_modules:
|
||||||
web_node_modules:
|
web_node_modules:
|
||||||
upload1-devcontainer-volume:
|
upload-devcontainer-volume:
|
||||||
upload2-devcontainer-volume:
|
|
||||||
postgres-devcontainer-volume:
|
|
||||||
|
|||||||
@@ -6,11 +6,7 @@ design/
|
|||||||
docker/
|
docker/
|
||||||
!docker/scripts
|
!docker/scripts
|
||||||
docs/
|
docs/
|
||||||
!docs/package.json
|
|
||||||
!docs/package-lock.json
|
|
||||||
e2e/
|
e2e/
|
||||||
!e2e/package.json
|
|
||||||
!e2e/package-lock.json
|
|
||||||
fastlane/
|
fastlane/
|
||||||
machine-learning/
|
machine-learning/
|
||||||
misc/
|
misc/
|
||||||
|
|||||||
2
.github/workflows/build-mobile.yml
vendored
2
.github/workflows/build-mobile.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
|||||||
cache: 'gradle'
|
cache: 'gradle'
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
|
|||||||
7
.github/workflows/cli.yml
vendored
7
.github/workflows/cli.yml
vendored
@@ -38,9 +38,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Prepare SDK
|
- name: Prepare SDK
|
||||||
run: npm ci --prefix ../open-api/typescript-sdk/
|
run: npm ci --prefix ../open-api/typescript-sdk/
|
||||||
- name: Build SDK
|
- name: Build SDK
|
||||||
@@ -70,7 +67,7 @@ jobs:
|
|||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
@@ -99,7 +96,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
- name: Build and push image
|
- name: Build and push image
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
||||||
with:
|
with:
|
||||||
file: cli/Dockerfile
|
file: cli/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -76,6 +76,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
category: '/language:${{matrix.language}}'
|
category: '/language:${{matrix.language}}'
|
||||||
|
|||||||
4
.github/workflows/docker.yml
vendored
4
.github/workflows/docker.yml
vendored
@@ -177,7 +177,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|
||||||
@@ -188,6 +188,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|||||||
2
.github/workflows/docs-build.yml
vendored
2
.github/workflows/docs-build.yml
vendored
@@ -57,8 +57,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './docs/.nvmrc'
|
node-version-file: './docs/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
2
.github/workflows/fix-format.yml
vendored
2
.github/workflows/fix-format.yml
vendored
@@ -32,8 +32,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Fix formatting
|
- name: Fix formatting
|
||||||
run: make install-all && make format-all
|
run: make install-all && make format-all
|
||||||
|
|||||||
2
.github/workflows/prepare-release.yml
vendored
2
.github/workflows/prepare-release.yml
vendored
@@ -100,7 +100,7 @@ jobs:
|
|||||||
name: release-apk-signed
|
name: release-apk-signed
|
||||||
|
|
||||||
- name: Create draft release
|
- name: Create draft release
|
||||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
|
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
tag_name: ${{ env.IMMICH_VERSION }}
|
tag_name: ${{ env.IMMICH_VERSION }}
|
||||||
|
|||||||
2
.github/workflows/sdk.yml
vendored
2
.github/workflows/sdk.yml
vendored
@@ -25,8 +25,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
6
.github/workflows/static_analysis.yml
vendored
6
.github/workflows/static_analysis.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -109,7 +109,7 @@ jobs:
|
|||||||
working-directory: ./mobile
|
working-directory: ./mobile
|
||||||
|
|
||||||
- name: Run DCM
|
- name: Run DCM
|
||||||
run: dcm analyze lib --fatal-style --fatal-warnings
|
run: dcm analyze lib
|
||||||
working-directory: ./mobile
|
working-directory: ./mobile
|
||||||
|
|
||||||
zizmor:
|
zizmor:
|
||||||
@@ -134,7 +134,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: zizmor
|
category: zizmor
|
||||||
|
|||||||
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
@@ -84,8 +84,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -127,8 +125,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Setup typescript-sdk
|
- name: Setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -174,8 +170,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './cli/.nvmrc'
|
node-version-file: './cli/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Setup typescript-sdk
|
- name: Setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -214,8 +208,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -257,8 +249,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -292,8 +282,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './web/.nvmrc'
|
node-version-file: './web/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm --prefix=web ci
|
run: npm --prefix=web ci
|
||||||
@@ -338,8 +326,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -383,8 +369,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -418,8 +402,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -468,8 +450,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './e2e/.nvmrc'
|
node-version-file: './e2e/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run setup typescript-sdk
|
- name: Run setup typescript-sdk
|
||||||
run: npm ci && npm run build
|
run: npm ci && npm run build
|
||||||
@@ -481,7 +461,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: npx playwright install chromium --only-shell
|
run: npx playwright install --with-deps chromium
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Docker build
|
- name: Docker build
|
||||||
@@ -499,7 +479,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|
||||||
@@ -516,7 +496,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Flutter SDK
|
- name: Setup Flutter SDK
|
||||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||||
with:
|
with:
|
||||||
channel: 'stable'
|
channel: 'stable'
|
||||||
flutter-version-file: ./mobile/pubspec.yaml
|
flutter-version-file: ./mobile/pubspec.yaml
|
||||||
@@ -588,8 +568,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './.github/.nvmrc'
|
node-version-file: './.github/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Run npm install
|
- name: Run npm install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -631,8 +609,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm --prefix=server ci
|
run: npm --prefix=server ci
|
||||||
@@ -668,7 +644,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:1f5583fe3397210a0fbc7f11b0cec18bacc4a99e3e8ea0548e9bd6bcf26ec37a
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
@@ -694,8 +670,6 @@ jobs:
|
|||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version-file: './server/.nvmrc'
|
node-version-file: './server/.nvmrc'
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: '**/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install server dependencies
|
- name: Install server dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
2
.github/workflows/weblate-lock.yml
vendored
2
.github/workflows/weblate-lock.yml
vendored
@@ -52,6 +52,6 @@ jobs:
|
|||||||
permissions: {}
|
permissions: {}
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
|
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
|
||||||
with:
|
with:
|
||||||
needs: ${{ toJSON(needs) }}
|
needs: ${{ toJSON(needs) }}
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -48,8 +48,6 @@ audit-%:
|
|||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||||
install-%:
|
install-%:
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
||||||
ci-%:
|
|
||||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) ci
|
|
||||||
build-cli: build-sdk
|
build-cli: build-sdk
|
||||||
build-web: build-sdk
|
build-web: build-sdk
|
||||||
build-%: install-%
|
build-%: install-%
|
||||||
@@ -83,8 +81,7 @@ test-medium-dev:
|
|||||||
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
||||||
|
|
||||||
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
||||||
install-all: $(foreach M,$(filter-out .github,$(MODULES)),install-$M) ;
|
install-all: $(foreach M,$(MODULES),install-$M) ;
|
||||||
ci-all: $(foreach M,$(filter-out .github,$(MODULES)),ci-$M) ;
|
|
||||||
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
|
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
|
||||||
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
|
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
|
||||||
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
format-all: $(foreach M,$(filter-out sdk,$(MODULES)),format-$M) ;
|
||||||
|
|||||||
10
cli/package-lock.json
generated
10
cli/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"chokidar": "^4.0.3",
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
"byte-size": "^9.0.0",
|
"byte-size": "^9.0.0",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
@@ -54,14 +54,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
"byte-size": "^9.0.0",
|
"byte-size": "^9.0.0",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ name: immich-dev
|
|||||||
services:
|
services:
|
||||||
immich-server:
|
immich-server:
|
||||||
container_name: immich_server
|
container_name: immich_server
|
||||||
command: ['/usr/src/app/bin/immich-dev']
|
command: [ '/usr/src/app/bin/immich-dev' ]
|
||||||
image: immich-server-dev:latest
|
image: immich-server-dev:latest
|
||||||
# extends:
|
# extends:
|
||||||
# file: hwaccel.transcoding.yml
|
# file: hwaccel.transcoding.yml
|
||||||
@@ -70,7 +70,7 @@ services:
|
|||||||
# user: 0:0
|
# user: 0:0
|
||||||
build:
|
build:
|
||||||
context: ../web
|
context: ../web
|
||||||
command: ['/usr/src/app/bin/immich-web']
|
command: [ '/usr/src/app/bin/immich-web' ]
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
ports:
|
ports:
|
||||||
@@ -122,7 +122,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -91,10 +91,10 @@ services:
|
|||||||
# add data source for http://immich-prometheus:9090 to get started
|
# add data source for http://immich-prometheus:9090 to get started
|
||||||
immich-grafana:
|
immich-grafana:
|
||||||
container_name: immich_grafana
|
container_name: immich_grafana
|
||||||
command: ['./run.sh', '-disable-reporting']
|
command: [ './run.sh', '-disable-reporting' ]
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
image: grafana/grafana:12.0.2-ubuntu@sha256:0512d81cdeaaff0e370a9aa66027b465d1f1f04379c3a9c801a905fabbdbc7a5
|
image: grafana/grafana:12.0.1-ubuntu@sha256:65575bb9c761335e2ff30e364f21d38632e3b2e75f5f81d83cc92f44b9bbc055
|
||||||
volumes:
|
volumes:
|
||||||
- grafana-data:/var/lib/grafana
|
- grafana-data:/var/lib/grafana
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1-pgvectors0.2.0
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
POSTGRES_USER: ${DB_USERNAME}
|
POSTGRES_USER: ${DB_USERNAME}
|
||||||
|
|||||||
@@ -64,13 +64,7 @@ COMMIT;
|
|||||||
|
|
||||||
### Updating VectorChord
|
### Updating VectorChord
|
||||||
|
|
||||||
When installing a new version of VectorChord, you will need to manually update the extension and reindex by connecting to the Immich database and running:
|
When installing a new version of VectorChord, you will need to manually update the extension by connecting to the Immich database and running `ALTER EXTENSION vchord UPDATE;`.
|
||||||
|
|
||||||
```
|
|
||||||
ALTER EXTENSION vchord UPDATE;
|
|
||||||
REINDEX INDEX face_index;
|
|
||||||
REINDEX INDEX clip_index;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migrating to VectorChord
|
## Migrating to VectorChord
|
||||||
|
|
||||||
@@ -82,8 +76,6 @@ Support for pgvecto.rs will be dropped in a later release, hence we recommend al
|
|||||||
|
|
||||||
The easiest option is to have both extensions installed during the migration:
|
The easiest option is to have both extensions installed during the migration:
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps (automatic)</summary>
|
|
||||||
1. Ensure you still have pgvecto.rs installed
|
1. Ensure you still have pgvecto.rs installed
|
||||||
2. Install `pgvector` (`>= 0.7.0, < 1.0.0`). The easiest way to do this is on Debian/Ubuntu by adding the [PostgreSQL Apt repository][pg-apt] and then running `apt install postgresql-NN-pgvector`, where `NN` is your Postgres version (e.g., `16`)
|
2. Install `pgvector` (`>= 0.7.0, < 1.0.0`). The easiest way to do this is on Debian/Ubuntu by adding the [PostgreSQL Apt repository][pg-apt] and then running `apt install postgresql-NN-pgvector`, where `NN` is your Postgres version (e.g., `16`)
|
||||||
3. [Install VectorChord][vchord-install]
|
3. [Install VectorChord][vchord-install]
|
||||||
@@ -97,12 +89,8 @@ The easiest option is to have both extensions installed during the migration:
|
|||||||
11. Restart the Postgres database
|
11. Restart the Postgres database
|
||||||
12. Uninstall pgvecto.rs (e.g. `apt-get purge vectors-pg14` on Debian-based environments, replacing `pg14` as appropriate). `pgvector` must remain installed as it provides the data types used by `vchord`
|
12. Uninstall pgvecto.rs (e.g. `apt-get purge vectors-pg14` on Debian-based environments, replacing `pg14` as appropriate). `pgvector` must remain installed as it provides the data types used by `vchord`
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
If it is not possible to have both VectorChord and pgvecto.rs installed at the same time, you can perform the migration with more manual steps:
|
If it is not possible to have both VectorChord and pgvecto.rs installed at the same time, you can perform the migration with more manual steps:
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps (manual)</summary>
|
|
||||||
1. While pgvecto.rs is still installed, run the following SQL command using psql or your choice of database client. Take note of the number outputted by this command as you will need it later
|
1. While pgvecto.rs is still installed, run the following SQL command using psql or your choice of database client. Take note of the number outputted by this command as you will need it later
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -135,20 +123,14 @@ ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512);
|
|||||||
|
|
||||||
5. Start Immich and let it create new indices using VectorChord
|
5. Start Immich and let it create new indices using VectorChord
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Migrating from pgvector
|
### Migrating from pgvector
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Migration steps</summary>
|
|
||||||
1. Ensure you have at least 0.7.0 of pgvector installed. If it is below that, please upgrade it and run the SQL command `ALTER EXTENSION vector UPDATE;` using psql or your choice of database client
|
1. Ensure you have at least 0.7.0 of pgvector installed. If it is below that, please upgrade it and run the SQL command `ALTER EXTENSION vector UPDATE;` using psql or your choice of database client
|
||||||
2. Follow the Prerequisites to install VectorChord
|
2. Follow the Prerequisites to install VectorChord
|
||||||
3. If Immich does not have superuser permissions, run the SQL command `CREATE EXTENSION vchord CASCADE;`
|
3. If Immich does not have superuser permissions, run the SQL command `CREATE EXTENSION vchord CASCADE;`
|
||||||
4. Remove the `DB_VECTOR_EXTENSION=pgvector` environmental variable as it will make Immich still use pgvector if set
|
4. Remove the `DB_VECTOR_EXTENSION=pgvector` environmental variable as it will make Immich still use pgvector if set
|
||||||
5. Start Immich and let it create new indices using VectorChord
|
5. Start Immich and let it create new indices using VectorChord
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
Note that VectorChord itself uses pgvector types, so you should not uninstall pgvector after following these steps.
|
Note that VectorChord itself uses pgvector types, so you should not uninstall pgvector after following these steps.
|
||||||
|
|
||||||
[vchord-install]: https://docs.vectorchord.ai/vectorchord/getting-started/installation.html
|
[vchord-install]: https://docs.vectorchord.ai/vectorchord/getting-started/installation.html
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ alt="Dot Env Example"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
||||||
- Change `DB_DATA_LOCATION` to a folder (absolute path) where the database will be saved to disk.
|
- Change `DB_DATA_LOCATION` to a folder where the database will be saved to disk.
|
||||||
- Change `UPLOAD_LOCATION` to a folder (absolute path) where media (uploaded and generated) will be stored.
|
- Change `UPLOAD_LOCATION` to a folder where media (uploaded and generated) will be stored.
|
||||||
|
|
||||||
11. Click on "**Deploy the stack**".
|
11. Click on "**Deploy the stack**".
|
||||||
|
|
||||||
|
|||||||
12
docs/static/archived-versions.json
vendored
12
docs/static/archived-versions.json
vendored
@@ -1,16 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"label": "v1.135.3",
|
|
||||||
"url": "https://v1.135.3.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.2",
|
|
||||||
"url": "https://v1.135.2.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.1",
|
|
||||||
"url": "https://v1.135.1.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "v1.135.0",
|
"label": "v1.135.0",
|
||||||
"url": "https://v1.135.0.archive.immich.app"
|
"url": "https://v1.135.0.archive.immich.app"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ services:
|
|||||||
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
|
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
|
||||||
|
|
||||||
database:
|
database:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:9c704fb49ce27549df00f1b096cc93f8b0c959ef087507704d74954808f78a82
|
||||||
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
|
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
|
|||||||
14
e2e/package-lock.json
generated
14
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"@types/oidc-provider": "^9.0.0",
|
"@types/oidc-provider": "^9.0.0",
|
||||||
"@types/pg": "^8.15.1",
|
"@types/pg": "^8.15.1",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
},
|
},
|
||||||
"../cli": {
|
"../cli": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
"@types/mock-fs": "^4.13.1",
|
"@types/mock-fs": "^4.13.1",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"@vitest/coverage-v8": "^3.0.0",
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
"byte-size": "^9.0.0",
|
"byte-size": "^9.0.0",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
@@ -93,14 +93,14 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oazapfts/runtime": "^1.0.2"
|
"@oazapfts/runtime": "^1.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@types/luxon": "^3.4.2",
|
"@types/luxon": "^3.4.2",
|
||||||
"@types/node": "^22.15.32",
|
"@types/node": "^22.15.31",
|
||||||
"@types/oidc-provider": "^9.0.0",
|
"@types/oidc-provider": "^9.0.0",
|
||||||
"@types/pg": "^8.15.1",
|
"@types/pg": "^8.15.1",
|
||||||
"@types/pngjs": "^6.0.4",
|
"@types/pngjs": "^6.0.4",
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ describe('/people', () => {
|
|||||||
let nameAlicePerson: PersonResponseDto;
|
let nameAlicePerson: PersonResponseDto;
|
||||||
let nameBobPerson: PersonResponseDto;
|
let nameBobPerson: PersonResponseDto;
|
||||||
let nameCharliePerson: PersonResponseDto;
|
let nameCharliePerson: PersonResponseDto;
|
||||||
let nameNullPerson4Assets: PersonResponseDto;
|
let nameNullPerson: PersonResponseDto;
|
||||||
let nameNullPerson3Assets: PersonResponseDto;
|
|
||||||
let nameNullPerson1Asset: PersonResponseDto;
|
|
||||||
let nameBillPersonFavourite: PersonResponseDto;
|
|
||||||
let nameFreddyPersonFavourite: PersonResponseDto;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await utils.resetDatabase();
|
await utils.resetDatabase();
|
||||||
@@ -31,11 +27,7 @@ describe('/people', () => {
|
|||||||
nameCharliePerson,
|
nameCharliePerson,
|
||||||
nameBobPerson,
|
nameBobPerson,
|
||||||
nameAlicePerson,
|
nameAlicePerson,
|
||||||
nameNullPerson4Assets,
|
nameNullPerson,
|
||||||
nameNullPerson3Assets,
|
|
||||||
nameNullPerson1Asset,
|
|
||||||
nameBillPersonFavourite,
|
|
||||||
nameFreddyPersonFavourite,
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: 'visible_person',
|
name: 'visible_person',
|
||||||
@@ -60,26 +52,11 @@ describe('/people', () => {
|
|||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: '',
|
name: '',
|
||||||
}),
|
}),
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Bill',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Freddy',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const asset1 = await utils.createAsset(admin.accessToken);
|
const asset1 = await utils.createAsset(admin.accessToken);
|
||||||
const asset2 = await utils.createAsset(admin.accessToken);
|
const asset2 = await utils.createAsset(admin.accessToken);
|
||||||
const asset3 = await utils.createAsset(admin.accessToken);
|
const asset3 = await utils.createAsset(admin.accessToken);
|
||||||
const asset4 = await utils.createAsset(admin.accessToken);
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
||||||
@@ -87,27 +64,15 @@ describe('/people', () => {
|
|||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }), // 4 assets
|
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }),
|
||||||
// Named persons
|
// Named persons
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
||||||
// Null-named person 4 assets
|
// Null-named person
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameNullPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset2.id, personId: nameNullPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson4Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset4.id, personId: nameNullPerson4Assets.id }), // 4 assets
|
|
||||||
// Null-named person 3 assets
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson3Assets.id }), // 3 assets
|
|
||||||
// Null-named person 1 asset
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson1Asset.id }),
|
|
||||||
// Favourite People
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBillPersonFavourite.id }),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,19 +87,15 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
expect.objectContaining({ name: 'hidden_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ name: 'hidden_person' }), // Should really be before the null names
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -144,21 +105,17 @@ describe('/people', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body.hasNextPage).toBe(false);
|
expect(body.hasNextPage).toBe(false);
|
||||||
expect(body.total).toBe(11); // All persons
|
expect(body.total).toBe(7); // All persons
|
||||||
expect(body.hidden).toBe(1); // 'hidden_person'
|
expect(body.hidden).toBe(1); // 'hidden_person'
|
||||||
|
|
||||||
const people = body.people as PersonResponseDto[];
|
const people = body.people as PersonResponseDto[];
|
||||||
|
|
||||||
expect(people.map((p) => p.id)).toEqual([
|
expect(people.map((p) => p.id)).toEqual([
|
||||||
nameFreddyPersonFavourite.id, // name: 'Freddy', count: 2
|
|
||||||
nameBillPersonFavourite.id, // name: 'Bill', count: 1
|
|
||||||
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
||||||
nameBobPerson.id, // name: 'Bob', count: 2
|
nameBobPerson.id, // name: 'Bob', count: 2
|
||||||
nameAlicePerson.id, // name: 'Alice', count: 1
|
nameAlicePerson.id, // name: 'Alice', count: 1
|
||||||
nameCharliePerson.id, // name: 'Charlie', count: 1
|
nameCharliePerson.id, // name: 'Charlie', count: 1
|
||||||
visiblePerson.id, // name: 'visible_person', count: 1
|
visiblePerson.id, // name: 'visible_person', count: 1
|
||||||
nameNullPerson4Assets.id, // name: '', count: 4
|
|
||||||
nameNullPerson3Assets.id, // name: '', count: 3
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
||||||
@@ -170,18 +127,14 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -195,9 +148,9 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [expect.objectContaining({ name: 'Alice' })],
|
people: [expect.objectContaining({ name: 'visible_person' })],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -119,16 +119,6 @@ describe('/shared-links', () => {
|
|||||||
expect(resp.header['content-type']).toContain('text/html');
|
expect(resp.header['content-type']).toContain('text/html');
|
||||||
expect(resp.text).toContain(`<meta property="og:image" content="https://my.immich.app`);
|
expect(resp.text).toContain(`<meta property="og:image" content="https://my.immich.app`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return 404 for an invalid shared link', async () => {
|
|
||||||
const resp = await request(shareUrl).get(`/invalid-key`);
|
|
||||||
expect(resp.status).toBe(404);
|
|
||||||
expect(resp.header['content-type']).toContain('text/html');
|
|
||||||
expect(resp.text).not.toContain(`og:type`);
|
|
||||||
expect(resp.text).not.toContain(`og:title`);
|
|
||||||
expect(resp.text).not.toContain(`og:description`);
|
|
||||||
expect(resp.text).not.toContain(`og:image`);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /shared-links', () => {
|
describe('GET /shared-links', () => {
|
||||||
|
|||||||
@@ -464,6 +464,7 @@
|
|||||||
"assets": "Assets",
|
"assets": "Assets",
|
||||||
"assets_added_count": "Added {count, plural, one {# asset} other {# assets}}",
|
"assets_added_count": "Added {count, plural, one {# asset} other {# assets}}",
|
||||||
"assets_added_to_album_count": "Added {count, plural, one {# asset} other {# assets}} to the album",
|
"assets_added_to_album_count": "Added {count, plural, one {# asset} other {# assets}} to the album",
|
||||||
|
"assets_added_to_name_count": "Added {count, plural, one {# asset} other {# assets}} to {hasName, select, true {<b>{name}</b>} other {new album}}",
|
||||||
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
|
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
|
||||||
"assets_count": "{count, plural, one {# asset} other {# assets}}",
|
"assets_count": "{count, plural, one {# asset} other {# assets}}",
|
||||||
"assets_deleted_permanently": "{count} asset(s) deleted permanently",
|
"assets_deleted_permanently": "{count} asset(s) deleted permanently",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
ARG DEVICE=cpu
|
ARG DEVICE=cpu
|
||||||
|
|
||||||
FROM python:3.11-bookworm@sha256:ce3b954c9285a7a145cba620bae03db836ab890b6b9e0d05a3ca522ea00dfbc9 AS builder-cpu
|
FROM python:3.11-bookworm@sha256:d2621a9f74d31a8a60af19f97b09cc3ac54382c8680b6544018713a12ef6c048 AS builder-cpu
|
||||||
|
|
||||||
FROM builder-cpu AS builder-openvino
|
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++
|
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:cda0fdc9b6066975ba4c791597870d18bc3a441dfc18ab24c5e888c16e15780c /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:4faec156e35a5f345d57804d8858c6ba1cf6352ce5f4bffc11b7fdebdef46a38 /uv /uvx /bin/
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
--mount=type=bind,source=uv.lock,target=uv.lock \
|
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
--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; \
|
uv pip install /opt/onnxruntime_rocm-*.whl; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FROM python:3.11-slim-bookworm@sha256:9e1912aab0a30bbd9488eb79063f68f42a68ab0946cbe98fecf197fe5b085506 AS prod-cpu
|
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-cpu
|
||||||
|
|
||||||
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
|
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
|
||||||
|
|
||||||
FROM python:3.11-slim-bookworm@sha256:9e1912aab0a30bbd9488eb79063f68f42a68ab0946cbe98fecf197fe5b085506 AS prod-openvino
|
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-openvino
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||||||
|
|
||||||
async def idle_shutdown_task() -> None:
|
async def idle_shutdown_task() -> None:
|
||||||
while True:
|
while True:
|
||||||
|
log.debug("Checking for inactivity...")
|
||||||
if (
|
if (
|
||||||
last_called is not None
|
last_called is not None
|
||||||
and not active_requests
|
and not active_requests
|
||||||
|
|||||||
141
machine-learning/uv.lock
generated
141
machine-learning/uv.lock
generated
@@ -517,16 +517,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.115.13"
|
version = "0.115.12"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "starlette" },
|
{ name = "starlette" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/20/64/ec0788201b5554e2a87c49af26b77a4d132f807a0fa9675257ac92c6aa0e/fastapi-0.115.13.tar.gz", hash = "sha256:55d1d25c2e1e0a0a50aceb1c8705cd932def273c102bff0b1c1da88b3c6eb307", size = 295680, upload-time = "2025-06-17T11:49:45.575Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/4a/e17764385382062b0edbb35a26b7cf76d71e27e456546277a42ba6545c6e/fastapi-0.115.13-py3-none-any.whl", hash = "sha256:0a0cab59afa7bab22f5eb347f8c9864b681558c278395e94035a741fc10cd865", size = 95315, upload-time = "2025-06-17T11:49:44.106Z" },
|
{ url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -900,7 +900,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "huggingface-hub"
|
name = "huggingface-hub"
|
||||||
version = "0.33.0"
|
version = "0.32.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "filelock" },
|
{ name = "filelock" },
|
||||||
@@ -912,9 +912,9 @@ dependencies = [
|
|||||||
{ name = "tqdm" },
|
{ name = "tqdm" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/91/8a/1362d565fefabaa4185cf3ae842a98dbc5b35146f5694f7080f043a6952f/huggingface_hub-0.33.0.tar.gz", hash = "sha256:aa31f70d29439d00ff7a33837c03f1f9dd83971ce4e29ad664d63ffb17d3bb97", size = 426179, upload-time = "2025-06-11T17:08:07.913Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/fb/53587a89fbc00799e4179796f51b3ad713c5de6bb680b2becb6d37c94649/huggingface_hub-0.33.0-py3-none-any.whl", hash = "sha256:e8668875b40c68f9929150d99727d39e5ebb8a05a98e4191b908dc7ded9074b3", size = 514799, upload-time = "2025-06-11T17:08:05.757Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -1225,7 +1225,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "locust"
|
name = "locust"
|
||||||
version = "2.37.11"
|
version = "2.37.9"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "configargparse" },
|
{ name = "configargparse" },
|
||||||
@@ -1245,14 +1245,14 @@ dependencies = [
|
|||||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "werkzeug" },
|
{ name = "werkzeug" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/4f/19/66cdab585f7d4385be615d3792402fc75a1bed7519e5283adbe7133dbc78/locust-2.37.11.tar.gz", hash = "sha256:89c79bc599aa57160bd41dd3876e35d8b9dee5abded78e35008d01fd8f1640ed", size = 2252602, upload-time = "2025-06-23T08:22:23.922Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/2d/e5ae05911521bf84113be349d51b16d54589e986837d2d518f63434ea3ec/locust-2.37.11-py3-none-any.whl", hash = "sha256:b826f95fbfd5d9a32df6ab1b74672b88e65bbc33ec99fdc10af98079952ad517", size = 2269179, upload-time = "2025-06-23T08:22:21.067Z" },
|
{ 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]]
|
[[package]]
|
||||||
name = "locust-cloud"
|
name = "locust-cloud"
|
||||||
version = "1.24.2"
|
version = "1.23.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "configargparse" },
|
{ name = "configargparse" },
|
||||||
@@ -1262,9 +1262,9 @@ dependencies = [
|
|||||||
{ name = "python-socketio", extra = ["client"] },
|
{ name = "python-socketio", extra = ["client"] },
|
||||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/77/bda24167a2b763ba5d3cad1f3fa2a938f5273e51a61bffdbc8dc2e3ba24d/locust_cloud-1.24.2.tar.gz", hash = "sha256:a2656537ff367e6d4d4673477ba9e81ed73a8423a71573cd2512248740eded77", size = 451122, upload-time = "2025-06-23T11:08:00.558Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/f4/38/8cda8aa1c6dfe5c5abbf69a9b10c03585c37eff64ca92733a291806052ac/locust_cloud-1.24.2-py3-none-any.whl", hash = "sha256:64a5e6f2bf0a1a012d9805291d44fb57e57535c2b5c0fa5bc87ba0d7cce9ef9c", size = 408594, upload-time = "2025-06-23T11:07:59.092Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -1415,7 +1415,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy"
|
name = "mypy"
|
||||||
version = "1.16.1"
|
version = "1.16.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "mypy-extensions" },
|
{ name = "mypy-extensions" },
|
||||||
@@ -1423,33 +1423,33 @@ dependencies = [
|
|||||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747, upload-time = "2025-06-16T16:51:35.145Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/12/2bf23a80fcef5edb75de9a1e295d778e0f46ea89eb8b115818b663eff42b/mypy-1.16.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4f0fed1022a63c6fec38f28b7fc77fca47fd490445c69d0a66266c59dd0b88a", size = 10958644, upload-time = "2025-06-16T16:51:11.649Z" },
|
{ 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/08/50/bfe47b3b278eacf348291742fd5e6613bbc4b3434b72ce9361896417cfe5/mypy-1.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86042bbf9f5a05ea000d3203cf87aa9d0ccf9a01f73f71c58979eb9249f46d72", size = 10087033, upload-time = "2025-06-16T16:35:30.089Z" },
|
{ 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/21/de/40307c12fe25675a0776aaa2cdd2879cf30d99eec91b898de00228dc3ab5/mypy-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea7469ee5902c95542bea7ee545f7006508c65c8c54b06dc2c92676ce526f3ea", size = 11875645, upload-time = "2025-06-16T16:35:48.49Z" },
|
{ 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/a6/d8/85bdb59e4a98b7a31495bd8f1a4445d8ffc86cde4ab1f8c11d247c11aedc/mypy-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:352025753ef6a83cb9e7f2427319bb7875d1fdda8439d1e23de12ab164179574", size = 12616986, upload-time = "2025-06-16T16:48:39.526Z" },
|
{ 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/0e/d0/bb25731158fa8f8ee9e068d3e94fcceb4971fedf1424248496292512afe9/mypy-1.16.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff9fa5b16e4c1364eb89a4d16bcda9987f05d39604e1e6c35378a2987c1aac2d", size = 12878632, upload-time = "2025-06-16T16:36:08.195Z" },
|
{ 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/2d/11/822a9beb7a2b825c0cb06132ca0a5183f8327a5e23ef89717c9474ba0bc6/mypy-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:1256688e284632382f8f3b9e2123df7d279f603c561f099758e66dd6ed4e8bd6", size = 9484391, upload-time = "2025-06-16T16:37:56.151Z" },
|
{ 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/9a/61/ec1245aa1c325cb7a6c0f8570a2eee3bfc40fa90d19b1267f8e50b5c8645/mypy-1.16.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:472e4e4c100062488ec643f6162dd0d5208e33e2f34544e1fc931372e806c0cc", size = 10890557, upload-time = "2025-06-16T16:37:21.421Z" },
|
{ 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/6b/bb/6eccc0ba0aa0c7a87df24e73f0ad34170514abd8162eb0c75fd7128171fb/mypy-1.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea16e2a7d2714277e349e24d19a782a663a34ed60864006e8585db08f8ad1782", size = 10012921, upload-time = "2025-06-16T16:51:28.659Z" },
|
{ 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/5f/80/b337a12e2006715f99f529e732c5f6a8c143bb58c92bb142d5ab380963a5/mypy-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08e850ea22adc4d8a4014651575567b0318ede51e8e9fe7a68f25391af699507", size = 11802887, upload-time = "2025-06-16T16:50:53.627Z" },
|
{ 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/d9/59/f7af072d09793d581a745a25737c7c0a945760036b16aeb620f658a017af/mypy-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22d76a63a42619bfb90122889b903519149879ddbf2ba4251834727944c8baca", size = 12531658, upload-time = "2025-06-16T16:33:55.002Z" },
|
{ 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/82/c4/607672f2d6c0254b94a646cfc45ad589dd71b04aa1f3d642b840f7cce06c/mypy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c7ce0662b6b9dc8f4ed86eb7a5d505ee3298c04b40ec13b30e572c0e5ae17c4", size = 12732486, upload-time = "2025-06-16T16:37:03.301Z" },
|
{ 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/b6/5e/136555ec1d80df877a707cebf9081bd3a9f397dedc1ab9750518d87489ec/mypy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:211287e98e05352a2e1d4e8759c5490925a7c784ddc84207f4714822f8cf99b6", size = 9479482, upload-time = "2025-06-16T16:47:37.48Z" },
|
{ 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/b4/d6/39482e5fcc724c15bf6280ff5806548c7185e0c090712a3736ed4d07e8b7/mypy-1.16.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:af4792433f09575d9eeca5c63d7d90ca4aeceda9d8355e136f80f8967639183d", size = 11066493, upload-time = "2025-06-16T16:47:01.683Z" },
|
{ 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/e6/e5/26c347890efc6b757f4d5bb83f4a0cf5958b8cf49c938ac99b8b72b420a6/mypy-1.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66df38405fd8466ce3517eda1f6640611a0b8e70895e2a9462d1d4323c5eb4b9", size = 10081687, upload-time = "2025-06-16T16:48:19.367Z" },
|
{ 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/44/c7/b5cb264c97b86914487d6a24bd8688c0172e37ec0f43e93b9691cae9468b/mypy-1.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44e7acddb3c48bd2713994d098729494117803616e116032af192871aed80b79", size = 11839723, upload-time = "2025-06-16T16:49:20.912Z" },
|
{ 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/15/f8/491997a9b8a554204f834ed4816bda813aefda31cf873bb099deee3c9a99/mypy-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ab5eca37b50188163fa7c1b73c685ac66c4e9bdee4a85c9adac0e91d8895e15", size = 12722980, upload-time = "2025-06-16T16:37:40.929Z" },
|
{ 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/df/f0/2bd41e174b5fd93bc9de9a28e4fb673113633b8a7f3a607fa4a73595e468/mypy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb6229b2c9086247e21a83c309754b9058b438704ad2f6807f0d8227f6ebdd", size = 12903328, upload-time = "2025-06-16T16:34:35.099Z" },
|
{ 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/61/81/5572108a7bec2c46b8aff7e9b524f371fe6ab5efb534d38d6b37b5490da8/mypy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:1f0435cf920e287ff68af3d10a118a73f212deb2ce087619eb4e648116d1fe9b", size = 9562321, upload-time = "2025-06-16T16:48:58.823Z" },
|
{ 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/28/e3/96964af4a75a949e67df4b95318fe2b7427ac8189bbc3ef28f92a1c5bc56/mypy-1.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddc91eb318c8751c69ddb200a5937f1232ee8efb4e64e9f4bc475a33719de438", size = 11063480, upload-time = "2025-06-16T16:47:56.205Z" },
|
{ 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/f5/4d/cd1a42b8e5be278fab7010fb289d9307a63e07153f0ae1510a3d7b703193/mypy-1.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:87ff2c13d58bdc4bbe7dc0dedfe622c0f04e2cb2a492269f3b418df2de05c536", size = 10090538, upload-time = "2025-06-16T16:46:43.92Z" },
|
{ 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/c9/4f/c3c6b4b66374b5f68bab07c8cabd63a049ff69796b844bc759a0ca99bb2a/mypy-1.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a7cfb0fe29fe5a9841b7c8ee6dffb52382c45acdf68f032145b75620acfbd6f", size = 11836839, upload-time = "2025-06-16T16:36:28.039Z" },
|
{ 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/b4/7e/81ca3b074021ad9775e5cb97ebe0089c0f13684b066a750b7dc208438403/mypy-1.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:051e1677689c9d9578b9c7f4d206d763f9bbd95723cd1416fad50db49d52f359", size = 12715634, upload-time = "2025-06-16T16:50:34.441Z" },
|
{ 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/e9/95/bdd40c8be346fa4c70edb4081d727a54d0a05382d84966869738cfa8a497/mypy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5d2309511cc56c021b4b4e462907c2b12f669b2dbeb68300110ec27723971be", size = 12895584, upload-time = "2025-06-16T16:34:54.857Z" },
|
{ 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/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee", size = 9573886, upload-time = "2025-06-16T16:36:43.589Z" },
|
{ 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/cf/d3/53e684e78e07c1a2bf7105715e5edd09ce951fc3f47cf9ed095ec1b7a037/mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37", size = 2265923, upload-time = "2025-06-16T16:48:02.366Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -1834,7 +1834,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.11.7"
|
version = "2.11.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-types" },
|
{ name = "annotated-types" },
|
||||||
@@ -1842,9 +1842,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "typing-inspection" },
|
{ name = "typing-inspection" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102, upload-time = "2025-05-22T21:18:08.761Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
|
{ url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229, upload-time = "2025-05-22T21:18:06.329Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1977,7 +1977,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "8.4.1"
|
version = "8.4.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
@@ -1988,9 +1988,9 @@ dependencies = [
|
|||||||
{ name = "pygments" },
|
{ name = "pygments" },
|
||||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -2007,16 +2007,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-cov"
|
name = "pytest-cov"
|
||||||
version = "6.2.1"
|
version = "6.1.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "coverage", extra = ["toml"] },
|
{ name = "coverage", extra = ["toml"] },
|
||||||
{ name = "pluggy" },
|
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/25/69/5f1e57f6c5a39f81411b550027bf72842c4567ff5fd572bed1edc9e4b5d9/pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a", size = 66857, upload-time = "2025-04-05T14:07:51.592Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" },
|
{ url = "https://files.pythonhosted.org/packages/28/d0/def53b4a790cfb21483016430ed828f64830dd981ebe1089971cd10cab25/pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde", size = 23841, upload-time = "2025-04-05T14:07:49.641Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2304,27 +2303,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.12.0"
|
version = "0.11.13"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/24/90/5255432602c0b196a0da6720f6f76b93eb50baef46d3c9b0025e2f9acbf3/ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c", size = 4376101, upload-time = "2025-06-17T15:19:26.217Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e6/fd/b46bb20e14b11ff49dbc74c61de352e0dc07fb650189513631f6fb5fc69f/ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848", size = 10311554, upload-time = "2025-06-17T15:18:45.792Z" },
|
{ 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/e7/d3/021dde5a988fa3e25d2468d1dadeea0ae89dc4bc67d0140c6e68818a12a1/ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6", size = 11118435, upload-time = "2025-06-17T15:18:49.064Z" },
|
{ 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/07/a2/01a5acf495265c667686ec418f19fd5c32bcc326d4c79ac28824aecd6a32/ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0", size = 10466010, upload-time = "2025-06-17T15:18:51.341Z" },
|
{ 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/4c/57/7caf31dd947d72e7aa06c60ecb19c135cad871a0a8a251723088132ce801/ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48", size = 10661366, upload-time = "2025-06-17T15:18:53.29Z" },
|
{ 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/e9/ba/aa393b972a782b4bc9ea121e0e358a18981980856190d7d2b6187f63e03a/ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807", size = 10173492, upload-time = "2025-06-17T15:18:55.262Z" },
|
{ 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/d7/50/9349ee777614bc3062fc6b038503a59b2034d09dd259daf8192f56c06720/ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82", size = 11761739, upload-time = "2025-06-17T15:18:58.906Z" },
|
{ 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/04/8f/ad459de67c70ec112e2ba7206841c8f4eb340a03ee6a5cabc159fe558b8e/ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c", size = 12537098, upload-time = "2025-06-17T15:19:01.316Z" },
|
{ 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/ed/50/15ad9c80ebd3c4819f5bd8883e57329f538704ed57bac680d95cb6627527/ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165", size = 12154122, upload-time = "2025-06-17T15:19:03.727Z" },
|
{ 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/76/e6/79b91e41bc8cc3e78ee95c87093c6cacfa275c786e53c9b11b9358026b3d/ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2", size = 11363374, upload-time = "2025-06-17T15:19:05.875Z" },
|
{ 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/db/c3/82b292ff8a561850934549aa9dc39e2c4e783ab3c21debe55a495ddf7827/ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4", size = 11587647, upload-time = "2025-06-17T15:19:08.246Z" },
|
{ 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/2b/42/d5760d742669f285909de1bbf50289baccb647b53e99b8a3b4f7ce1b2001/ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514", size = 10527284, upload-time = "2025-06-17T15:19:10.37Z" },
|
{ 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/19/f6/fcee9935f25a8a8bba4adbae62495c39ef281256693962c2159e8b284c5f/ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88", size = 10158609, upload-time = "2025-06-17T15:19:12.286Z" },
|
{ 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/37/fb/057febf0eea07b9384787bfe197e8b3384aa05faa0d6bd844b94ceb29945/ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51", size = 11141462, upload-time = "2025-06-17T15:19:15.195Z" },
|
{ 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/10/7c/1be8571011585914b9d23c95b15d07eec2d2303e94a03df58294bc9274d4/ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a", size = 11641616, upload-time = "2025-06-17T15:19:17.6Z" },
|
{ 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/6a/ef/b960ab4818f90ff59e571d03c3f992828d4683561095e80f9ef31f3d58b7/ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb", size = 10525289, upload-time = "2025-06-17T15:19:19.688Z" },
|
{ 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/34/93/8b16034d493ef958a500f17cda3496c63a537ce9d5a6479feec9558f1695/ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0", size = 11598311, upload-time = "2025-06-17T15:19:21.785Z" },
|
{ 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/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -2559,14 +2558,14 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "types-requests"
|
name = "types-requests"
|
||||||
version = "2.32.4.20250611"
|
version = "2.32.0.20250602"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "urllib3" },
|
{ name = "urllib3" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" },
|
{ 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]]
|
[[package]]
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ dart_code_metrics:
|
|||||||
# - no-empty-block
|
# - no-empty-block
|
||||||
# - no-equal-then-else
|
# - no-equal-then-else
|
||||||
# - prefer-correct-test-file-name
|
# - prefer-correct-test-file-name
|
||||||
- prefer-const-border-radius
|
|
||||||
# - prefer-match-file-name
|
# - prefer-match-file-name
|
||||||
# - prefer-return-await
|
# - prefer-return-await
|
||||||
# - avoid-self-assignment
|
# - avoid-self-assignment
|
||||||
@@ -291,8 +290,7 @@ dart_code_metrics:
|
|||||||
# Style
|
# Style
|
||||||
# - prefer-trailing-comma
|
# - prefer-trailing-comma
|
||||||
# - unnecessary-trailing-comma
|
# - unnecessary-trailing-comma
|
||||||
- prefer-declaring-const-constructor
|
# - prefer-declaring-const-constructor
|
||||||
# - prefer-single-widget-per-file
|
# - prefer-single-widget-per-file
|
||||||
- prefer-switch-expression
|
|
||||||
# - prefer-prefixed-global-constants
|
# - prefer-prefixed-global-constants
|
||||||
# - prefer-correct-callback-field-name
|
# - prefer-correct-callback-field-name
|
||||||
|
|||||||
@@ -90,35 +90,6 @@
|
|||||||
<data android:mimeType="video/*" />
|
<data android:mimeType="video/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<!-- immich:// URL scheme handling -->
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<data android:scheme="immich" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<!-- my.immich.app deep link -->
|
|
||||||
<intent-filter android:autoVerify="true">
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="https" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:host="my.immich.app"
|
|
||||||
android:path="/" />
|
|
||||||
<data
|
|
||||||
android:host="my.immich.app"
|
|
||||||
android:pathPrefix="/albums/" />
|
|
||||||
<data
|
|
||||||
android:host="my.immich.app"
|
|
||||||
android:pathPrefix="/memories/" />
|
|
||||||
<data
|
|
||||||
android:host="my.immich.app"
|
|
||||||
android:pathPrefix="/photos/" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 204,
|
"android.injected.version.code" => 201,
|
||||||
"android.injected.version.name" => "1.135.3",
|
"android.injected.version.name" => "1.135.0",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'general_helper.dart';
|
|||||||
class ImmichTestLoginHelper {
|
class ImmichTestLoginHelper {
|
||||||
final WidgetTester tester;
|
final WidgetTester tester;
|
||||||
|
|
||||||
const ImmichTestLoginHelper(this.tester);
|
ImmichTestLoginHelper(this.tester);
|
||||||
|
|
||||||
Future<void> waitForLoginScreen() async {
|
Future<void> waitForLoginScreen() async {
|
||||||
await pumpUntilFound(tester, find.text("Login"));
|
await pumpUntilFound(tester, find.text("Login"));
|
||||||
@@ -60,11 +60,11 @@ class ImmichTestLoginHelper {
|
|||||||
await tester.tap(button);
|
await tester.tap(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> assertLoginSuccess() async {
|
Future<void> assertLoginSuccess({int timeoutSeconds = 15}) async {
|
||||||
await pumpUntilFound(tester, find.text("home_page_building_timeline".tr()));
|
await pumpUntilFound(tester, find.text("home_page_building_timeline".tr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> assertLoginFailed() async {
|
Future<void> assertLoginFailed({int timeoutSeconds = 15}) async {
|
||||||
await pumpUntilFound(tester, find.text("login_form_failed_login".tr()));
|
await pumpUntilFound(tester, find.text("login_form_failed_login".tr()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,7 +346,6 @@
|
|||||||
};
|
};
|
||||||
F0B57D372DF764BD00DC5BCC = {
|
F0B57D372DF764BD00DC5BCC = {
|
||||||
CreatedOnToolsVersion = 16.4;
|
CreatedOnToolsVersion = 16.4;
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
};
|
};
|
||||||
FAC6F88F2D287C890078CB2F = {
|
FAC6F88F2D287C890078CB2F = {
|
||||||
CreatedOnToolsVersion = 16.0;
|
CreatedOnToolsVersion = 16.0;
|
||||||
@@ -649,7 +648,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -793,7 +792,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -823,7 +822,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -857,7 +856,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -865,7 +864,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -900,7 +899,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -908,7 +907,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -940,7 +939,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -948,7 +947,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -979,7 +978,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
@@ -1023,7 +1022,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
@@ -1064,7 +1063,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 208;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.135.1</string>
|
<string>1.134.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
@@ -86,26 +86,14 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>Share Extension</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>Deep Link</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>immich</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>210</string>
|
<string>208</string>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
<true />
|
<true />
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
@@ -127,13 +115,11 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>NSBonjourServices</key>
|
<key>NSBonjourServices</key>
|
||||||
<array>
|
<array>
|
||||||
<string>_googlecast._tcp</string>
|
<string>_googlecast._tcp</string>
|
||||||
<string>_CC1AD845._googlecast._tcp</string>
|
<string>_CC1AD845._googlecast._tcp</string>
|
||||||
</array>
|
</array>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||||
<key>NSFaceIDUsageDescription</key>
|
|
||||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
|
||||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||||
<string>We require this permission to access the local WiFi name for background upload mechanism</string>
|
<string>We require this permission to access the local WiFi name for background upload mechanism</string>
|
||||||
<key>NSLocationUsageDescription</key>
|
<key>NSLocationUsageDescription</key>
|
||||||
@@ -180,8 +166,7 @@
|
|||||||
<true />
|
<true />
|
||||||
<key>io.flutter.embedded_views_preview</key>
|
<key>io.flutter.embedded_views_preview</key>
|
||||||
<true />
|
<true />
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
<key>NSFaceIDUsageDescription</key>
|
||||||
<string>We need local network permission to connect to the local server using IP address and
|
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||||
allow the casting feature to work</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.developer.associated-domains</key>
|
|
||||||
<array>
|
|
||||||
<string>applinks:my.immich.app</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.developer.networking.wifi-info</key>
|
<key>com.apple.developer.networking.wifi-info</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>aps-environment</key>
|
<key>aps-environment</key>
|
||||||
<string>development</string>
|
<string>development</string>
|
||||||
<key>com.apple.developer.associated-domains</key>
|
|
||||||
<array>
|
|
||||||
<string>applinks:my.immich.app</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.developer.networking.wifi-info</key>
|
<key>com.apple.developer.networking.wifi-info</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
|
|||||||
@@ -24,11 +24,27 @@ struct ImageEntry: TimelineEntry {
|
|||||||
struct ImmichWidgetView: View {
|
struct ImmichWidgetView: View {
|
||||||
var entry: ImageEntry
|
var entry: ImageEntry
|
||||||
|
|
||||||
|
func getErrorText(_ error: WidgetError?) -> String {
|
||||||
|
switch error {
|
||||||
|
case .noLogin:
|
||||||
|
return "Login to Immich"
|
||||||
|
|
||||||
|
case .fetchFailed:
|
||||||
|
return "Unable to connect to your Immich instance"
|
||||||
|
|
||||||
|
case .albumNotFound:
|
||||||
|
return "Album not found"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "An unknown error occured"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if entry.image == nil {
|
if entry.image == nil {
|
||||||
VStack {
|
VStack {
|
||||||
Image("LaunchImage")
|
Image("LaunchImage")
|
||||||
Text(entry.error?.errorDescription ?? "")
|
Text(getErrorText(entry.error))
|
||||||
.minimumScaleFactor(0.25)
|
.minimumScaleFactor(0.25)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
|
|||||||
@@ -8,32 +8,6 @@ enum WidgetError: Error {
|
|||||||
case unknown
|
case unknown
|
||||||
case albumNotFound
|
case albumNotFound
|
||||||
case unableToResize
|
case unableToResize
|
||||||
case invalidImage
|
|
||||||
case invalidURL
|
|
||||||
}
|
|
||||||
|
|
||||||
extension WidgetError: LocalizedError {
|
|
||||||
public var errorDescription: String? {
|
|
||||||
switch self {
|
|
||||||
case .noLogin:
|
|
||||||
return "Login to Immich"
|
|
||||||
|
|
||||||
case .fetchFailed:
|
|
||||||
return "Unable to connect to your Immich instance"
|
|
||||||
|
|
||||||
case .albumNotFound:
|
|
||||||
return "Album not found"
|
|
||||||
|
|
||||||
case .invalidURL:
|
|
||||||
return "An invalid URL was used"
|
|
||||||
|
|
||||||
case .invalidImage:
|
|
||||||
return "An invalid image was received"
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "An unknown error occured"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AssetType: String, Codable {
|
enum AssetType: String, Codable {
|
||||||
@@ -172,7 +146,7 @@ class ImmichAPI {
|
|||||||
return try JSONDecoder().decode([MemoryResult].self, from: data)
|
return try JSONDecoder().decode([MemoryResult].self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchImage(asset: SearchResult) async throws(WidgetError) -> UIImage {
|
func fetchImage(asset: SearchResult) async throws -> UIImage {
|
||||||
let thumbnailParams = [URLQueryItem(name: "size", value: "preview")]
|
let thumbnailParams = [URLQueryItem(name: "size", value: "preview")]
|
||||||
let assetEndpoint = "/assets/" + asset.id + "/thumbnail"
|
let assetEndpoint = "/assets/" + asset.id + "/thumbnail"
|
||||||
|
|
||||||
@@ -183,24 +157,16 @@ class ImmichAPI {
|
|||||||
params: thumbnailParams
|
params: thumbnailParams
|
||||||
)
|
)
|
||||||
else {
|
else {
|
||||||
throw .invalidURL
|
throw URLError(.badURL)
|
||||||
}
|
|
||||||
|
|
||||||
guard let imageSource = CGImageSourceCreateWithURL(fetchURL as CFURL, nil) else {
|
|
||||||
throw .invalidURL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let decodeOptions: [NSString: Any] = [
|
let (data, _) = try await URLSession.shared.data(from: fetchURL)
|
||||||
kCGImageSourceCreateThumbnailFromImageAlways: true,
|
|
||||||
kCGImageSourceThumbnailMaxPixelSize: 400,
|
guard let img = UIImage(data: data) else {
|
||||||
kCGImageSourceCreateThumbnailWithTransform: true
|
throw URLError(.badServerResponse)
|
||||||
]
|
|
||||||
|
|
||||||
guard let thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, decodeOptions as CFDictionary) else {
|
|
||||||
throw .fetchFailed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return UIImage(cgImage: thumbnail)
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAlbums() async throws -> [Album] {
|
func fetchAlbums() async throws -> [Album] {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct RandomConfigurationAppIntent: WidgetConfigurationIntent {
|
|||||||
"Choose an album to show images from"
|
"Choose an album to show images from"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parameter(title: "Album")
|
@Parameter(title: "Album", default: NO_ALBUM)
|
||||||
var album: Album?
|
var album: Album?
|
||||||
|
|
||||||
@Parameter(title: "Show Album Name", default: false)
|
@Parameter(title: "Show Album Name", default: false)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ platform :ios do
|
|||||||
path: "./Runner.xcodeproj",
|
path: "./Runner.xcodeproj",
|
||||||
)
|
)
|
||||||
increment_version_number(
|
increment_version_number(
|
||||||
version_number: "1.135.3"
|
version_number: "1.135.0"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
|||||||
@@ -10,5 +10,3 @@ enum TextSearchType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
||||||
|
|
||||||
enum SortUserBy { id }
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ sealed class ImmichErrors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NoResponseDtoError extends ImmichErrors implements Exception {
|
class NoResponseDtoError extends ImmichErrors implements Exception {
|
||||||
const NoResponseDtoError();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => "Response Dto is null";
|
String toString() => "Response Dto is null";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const Map<String, Locale> locales = {
|
|||||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
||||||
'Chinese Traditional (zh_TW)':
|
'Chinese Traditional (zh_TW)':
|
||||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||||
'Croatian (hr)': Locale('hr'),
|
|
||||||
'Czech (cs)': Locale('cs'),
|
'Czech (cs)': Locale('cs'),
|
||||||
'Danish (da)': Locale('da'),
|
'Danish (da)': Locale('da'),
|
||||||
'Dutch (nl)': Locale('nl'),
|
'Dutch (nl)': Locale('nl'),
|
||||||
|
|||||||
10
mobile/lib/domain/interfaces/asset_media.interface.dart
Normal file
10
mobile/lib/domain/interfaces/asset_media.interface.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
abstract interface class IAssetMediaRepository {
|
||||||
|
Future<Uint8List?> getThumbnail(
|
||||||
|
String id, {
|
||||||
|
int quality = 80,
|
||||||
|
Size size = const Size.square(256),
|
||||||
|
});
|
||||||
|
}
|
||||||
12
mobile/lib/domain/interfaces/device_asset.interface.dart
Normal file
12
mobile/lib/domain/interfaces/device_asset.interface.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IDeviceAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> updateAll(List<DeviceAsset> assetHash);
|
||||||
|
|
||||||
|
Future<List<DeviceAsset>> getByIds(List<String> localIds);
|
||||||
|
|
||||||
|
Future<void> deleteIds(List<String> ids);
|
||||||
|
}
|
||||||
14
mobile/lib/domain/interfaces/exif.interface.dart
Normal file
14
mobile/lib/domain/interfaces/exif.interface.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IExifInfoRepository implements IDatabaseRepository {
|
||||||
|
Future<ExifInfo?> get(int assetId);
|
||||||
|
|
||||||
|
Future<ExifInfo> update(ExifInfo exifInfo);
|
||||||
|
|
||||||
|
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos);
|
||||||
|
|
||||||
|
Future<void> delete(int assetId);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
33
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
33
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
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({Set<SortLocalAlbumsBy> sortBy = const {}});
|
||||||
|
|
||||||
|
Future<List<LocalAsset>> getAssets(String albumId);
|
||||||
|
|
||||||
|
Future<List<String>> getAssetIds(String albumId);
|
||||||
|
|
||||||
|
Future<void> upsert(
|
||||||
|
LocalAlbum album, {
|
||||||
|
Iterable<LocalAsset> toUpsert = const [],
|
||||||
|
Iterable<String> toDelete = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> updateAll(Iterable<LocalAlbum> albums);
|
||||||
|
|
||||||
|
Future<void> delete(String albumId);
|
||||||
|
|
||||||
|
Future<void> processDelta({
|
||||||
|
required List<LocalAsset> updates,
|
||||||
|
required List<String> deletes,
|
||||||
|
required Map<String, List<String>> assetAlbums,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> syncDeletes(String albumId, Iterable<String> assetIdsToKeep);
|
||||||
|
|
||||||
|
Future<List<LocalAsset>> getAssetsToHash(String albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
||||||
6
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
6
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<void> updateHashes(Iterable<LocalAsset> hashes);
|
||||||
|
}
|
||||||
17
mobile/lib/domain/interfaces/log.interface.dart
Normal file
17
mobile/lib/domain/interfaces/log.interface.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILogRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert(LogMessage log);
|
||||||
|
|
||||||
|
Future<bool> insertAll(Iterable<LogMessage> logs);
|
||||||
|
|
||||||
|
Future<List<LogMessage>> getAll();
|
||||||
|
|
||||||
|
Future<bool> deleteAll();
|
||||||
|
|
||||||
|
/// Truncates the logs to the most recent [limit]. Defaults to recent 250 logs
|
||||||
|
Future<void> truncate({int limit = 250});
|
||||||
|
}
|
||||||
7
mobile/lib/domain/interfaces/storage.interface.dart
Normal file
7
mobile/lib/domain/interfaces/storage.interface.dart
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IStorageRepository {
|
||||||
|
Future<File?> getFileForAsset(LocalAsset asset);
|
||||||
|
}
|
||||||
20
mobile/lib/domain/interfaces/store.interface.dart
Normal file
20
mobile/lib/domain/interfaces/store.interface.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IStoreRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert<T>(StoreKey<T> key, T value);
|
||||||
|
|
||||||
|
Future<T?> tryGet<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Future<List<StoreDto<Object>>> getAll();
|
||||||
|
|
||||||
|
Stream<T?> watch<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Stream<StoreDto<Object>> watchAll();
|
||||||
|
|
||||||
|
Future<bool> update<T>(StoreKey<T> key, T value);
|
||||||
|
|
||||||
|
Future<void> delete<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
12
mobile/lib/domain/interfaces/sync_api.interface.dart
Normal file
12
mobile/lib/domain/interfaces/sync_api.interface.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ISyncApiRepository {
|
||||||
|
Future<void> ack(List<String> data);
|
||||||
|
|
||||||
|
Future<void> streamChanges(
|
||||||
|
Function(List<SyncEvent>, Function() abort) onData, {
|
||||||
|
int batchSize,
|
||||||
|
http.Client? httpClient,
|
||||||
|
});
|
||||||
|
}
|
||||||
18
mobile/lib/domain/interfaces/sync_stream.interface.dart
Normal file
18
mobile/lib/domain/interfaces/sync_stream.interface.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
|
abstract interface class ISyncStreamRepository implements IDatabaseRepository {
|
||||||
|
Future<void> updateUsersV1(Iterable<SyncUserV1> data);
|
||||||
|
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data);
|
||||||
|
|
||||||
|
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data);
|
||||||
|
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data);
|
||||||
|
|
||||||
|
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data);
|
||||||
|
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data);
|
||||||
|
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data);
|
||||||
|
|
||||||
|
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data);
|
||||||
|
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data);
|
||||||
|
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data);
|
||||||
|
}
|
||||||
27
mobile/lib/domain/interfaces/timeline.interface.dart
Normal file
27
mobile/lib/domain/interfaces/timeline.interface.dart
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ITimelineRepository implements IDatabaseRepository {
|
||||||
|
Stream<List<Bucket>> watchMainBucket(
|
||||||
|
List<String> timelineUsers, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getMainBucketAssets(
|
||||||
|
List<String> timelineUsers, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
});
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchLocalBucket(
|
||||||
|
String albumId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getLocalBucketAssets(
|
||||||
|
String albumId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
});
|
||||||
|
}
|
||||||
22
mobile/lib/domain/interfaces/user.interface.dart
Normal file
22
mobile/lib/domain/interfaces/user.interface.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IUserRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert(UserDto user);
|
||||||
|
|
||||||
|
Future<UserDto?> getByUserId(String id);
|
||||||
|
|
||||||
|
Future<List<UserDto?>> getByUserIds(List<String> ids);
|
||||||
|
|
||||||
|
Future<List<UserDto>> getAll({SortUserBy? sortBy});
|
||||||
|
|
||||||
|
Future<bool> updateAll(List<UserDto> users);
|
||||||
|
|
||||||
|
Future<UserDto> update(UserDto user);
|
||||||
|
|
||||||
|
Future<void> delete(List<String> ids);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortUserBy { id }
|
||||||
15
mobile/lib/domain/interfaces/user_api.interface.dart
Normal file
15
mobile/lib/domain/interfaces/user_api.interface.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IUserApiRepository {
|
||||||
|
Future<UserDto?> getMyUser();
|
||||||
|
|
||||||
|
Future<List<UserDto>> getAll();
|
||||||
|
|
||||||
|
/// Saves the [data] in the server and uses it as the current users profile image
|
||||||
|
Future<String> createProfileImage({
|
||||||
|
required String name,
|
||||||
|
required Uint8List data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
|
||||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@@ -12,16 +12,16 @@ import 'package:logging/logging.dart';
|
|||||||
class HashService {
|
class HashService {
|
||||||
final int batchSizeLimit;
|
final int batchSizeLimit;
|
||||||
final int batchFileLimit;
|
final int batchFileLimit;
|
||||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
final ILocalAlbumRepository _localAlbumRepository;
|
||||||
final DriftLocalAssetRepository _localAssetRepository;
|
final ILocalAssetRepository _localAssetRepository;
|
||||||
final StorageRepository _storageRepository;
|
final IStorageRepository _storageRepository;
|
||||||
final NativeSyncApi _nativeSyncApi;
|
final NativeSyncApi _nativeSyncApi;
|
||||||
final _log = Logger('HashService');
|
final _log = Logger('HashService');
|
||||||
|
|
||||||
HashService({
|
HashService({
|
||||||
required DriftLocalAlbumRepository localAlbumRepository,
|
required ILocalAlbumRepository localAlbumRepository,
|
||||||
required DriftLocalAssetRepository localAssetRepository,
|
required ILocalAssetRepository localAssetRepository,
|
||||||
required StorageRepository storageRepository,
|
required IStorageRepository storageRepository,
|
||||||
required NativeSyncApi nativeSyncApi,
|
required NativeSyncApi nativeSyncApi,
|
||||||
this.batchSizeLimit = kBatchHashSizeLimit,
|
this.batchSizeLimit = kBatchHashSizeLimit,
|
||||||
this.batchFileLimit = kBatchHashFileLimit,
|
this.batchFileLimit = kBatchHashFileLimit,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
|
||||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:immich_mobile/utils/diff.dart';
|
import 'package:immich_mobile/utils/diff.dart';
|
||||||
@@ -14,14 +14,14 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
class LocalSyncService {
|
class LocalSyncService {
|
||||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
final ILocalAlbumRepository _localAlbumRepository;
|
||||||
final NativeSyncApi _nativeSyncApi;
|
final NativeSyncApi _nativeSyncApi;
|
||||||
final Platform _platform;
|
final Platform _platform;
|
||||||
final StoreService _storeService;
|
final StoreService _storeService;
|
||||||
final Logger _log = Logger("DeviceSyncService");
|
final Logger _log = Logger("DeviceSyncService");
|
||||||
|
|
||||||
LocalSyncService({
|
LocalSyncService({
|
||||||
required DriftLocalAlbumRepository localAlbumRepository,
|
required ILocalAlbumRepository localAlbumRepository,
|
||||||
required NativeSyncApi nativeSyncApi,
|
required NativeSyncApi nativeSyncApi,
|
||||||
required StoreService storeService,
|
required StoreService storeService,
|
||||||
Platform? platform,
|
Platform? platform,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
/// Service responsible for handling application logging.
|
/// Service responsible for handling application logging.
|
||||||
@@ -14,8 +14,8 @@ import 'package:logging/logging.dart';
|
|||||||
/// writes them to a persistent [ILogRepository], and manages log levels
|
/// writes them to a persistent [ILogRepository], and manages log levels
|
||||||
/// via [IStoreRepository]
|
/// via [IStoreRepository]
|
||||||
class LogService {
|
class LogService {
|
||||||
final IsarLogRepository _logRepository;
|
final ILogRepository _logRepository;
|
||||||
final IsarStoreRepository _storeRepository;
|
final IStoreRepository _storeRepository;
|
||||||
|
|
||||||
final List<LogMessage> _msgBuffer = [];
|
final List<LogMessage> _msgBuffer = [];
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ class LogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<LogService> init({
|
static Future<LogService> init({
|
||||||
required IsarLogRepository logRepository,
|
required ILogRepository logRepository,
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
_instance ??= await create(
|
_instance ??= await create(
|
||||||
@@ -50,8 +50,8 @@ class LogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<LogService> create({
|
static Future<LogService> create({
|
||||||
required IsarLogRepository logRepository,
|
required ILogRepository logRepository,
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
|
|
||||||
/// Provides access to a persistent key-value store with an in-memory cache.
|
/// Provides access to a persistent key-value store with an in-memory cache.
|
||||||
/// Listens for repository changes to keep the cache updated.
|
/// Listens for repository changes to keep the cache updated.
|
||||||
class StoreService {
|
class StoreService {
|
||||||
final IsarStoreRepository _storeRepository;
|
final IStoreRepository _storeRepository;
|
||||||
|
|
||||||
/// In-memory cache. Keys are [StoreKey.id]
|
/// In-memory cache. Keys are [StoreKey.id]
|
||||||
final Map<int, Object?> _cache = {};
|
final Map<int, Object?> _cache = {};
|
||||||
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
||||||
|
|
||||||
StoreService._({required IsarStoreRepository storeRepository})
|
StoreService._({required IStoreRepository storeRepository})
|
||||||
: _storeRepository = storeRepository;
|
: _storeRepository = storeRepository;
|
||||||
|
|
||||||
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
||||||
@@ -26,14 +26,14 @@ class StoreService {
|
|||||||
|
|
||||||
// TODO: Replace the implementation with the one from create after removing the typedef
|
// TODO: Replace the implementation with the one from create after removing the typedef
|
||||||
static Future<StoreService> init({
|
static Future<StoreService> init({
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
}) async {
|
}) async {
|
||||||
_instance ??= await create(storeRepository: storeRepository);
|
_instance ??= await create(storeRepository: storeRepository);
|
||||||
return _instance!;
|
return _instance!;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<StoreService> create({
|
static Future<StoreService> create({
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
}) async {
|
}) async {
|
||||||
final instance = StoreService._(storeRepository: storeRepository);
|
final instance = StoreService._(storeRepository: storeRepository);
|
||||||
await instance._populateCache();
|
await instance._populateCache();
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class SyncStreamService {
|
class SyncStreamService {
|
||||||
final Logger _logger = Logger('SyncStreamService');
|
final Logger _logger = Logger('SyncStreamService');
|
||||||
|
|
||||||
final SyncApiRepository _syncApiRepository;
|
final ISyncApiRepository _syncApiRepository;
|
||||||
final SyncStreamRepository _syncStreamRepository;
|
final ISyncStreamRepository _syncStreamRepository;
|
||||||
final bool Function()? _cancelChecker;
|
final bool Function()? _cancelChecker;
|
||||||
|
|
||||||
SyncStreamService({
|
SyncStreamService({
|
||||||
required SyncApiRepository syncApiRepository,
|
required ISyncApiRepository syncApiRepository,
|
||||||
required SyncStreamRepository syncStreamRepository,
|
required ISyncStreamRepository syncStreamRepository,
|
||||||
bool Function()? cancelChecker,
|
bool Function()? cancelChecker,
|
||||||
}) : _syncApiRepository = syncApiRepository,
|
}) : _syncApiRepository = syncApiRepository,
|
||||||
_syncStreamRepository = syncStreamRepository,
|
_syncStreamRepository = syncStreamRepository,
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import 'dart:math' as math;
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/setting.model.dart';
|
import 'package:immich_mobile/domain/models/setting.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/setting.service.dart';
|
import 'package:immich_mobile/domain/services/setting.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
|
|
||||||
import 'package:immich_mobile/utils/async_mutex.dart';
|
import 'package:immich_mobile/utils/async_mutex.dart';
|
||||||
|
|
||||||
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
||||||
@@ -18,11 +18,11 @@ typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
|||||||
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
||||||
|
|
||||||
class TimelineFactory {
|
class TimelineFactory {
|
||||||
final DriftTimelineRepository _timelineRepository;
|
final ITimelineRepository _timelineRepository;
|
||||||
final SettingsService _settingsService;
|
final SettingsService _settingsService;
|
||||||
|
|
||||||
const TimelineFactory({
|
const TimelineFactory({
|
||||||
required DriftTimelineRepository timelineRepository,
|
required ITimelineRepository timelineRepository,
|
||||||
required SettingsService settingsService,
|
required SettingsService settingsService,
|
||||||
}) : _timelineRepository = timelineRepository,
|
}) : _timelineRepository = timelineRepository,
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
final Logger _log = Logger("UserService");
|
final Logger _log = Logger("UserService");
|
||||||
final IsarUserRepository _isarUserRepository;
|
final IUserRepository _userRepository;
|
||||||
final UserApiRepository _userApiRepository;
|
final IUserApiRepository _userApiRepository;
|
||||||
final StoreService _storeService;
|
final StoreService _storeService;
|
||||||
|
|
||||||
UserService({
|
UserService({
|
||||||
required IsarUserRepository isarUserRepository,
|
required IUserRepository userRepository,
|
||||||
required UserApiRepository userApiRepository,
|
required IUserApiRepository userApiRepository,
|
||||||
required StoreService storeService,
|
required StoreService storeService,
|
||||||
}) : _isarUserRepository = isarUserRepository,
|
}) : _userRepository = userRepository,
|
||||||
_userApiRepository = userApiRepository,
|
_userApiRepository = userApiRepository,
|
||||||
_storeService = storeService;
|
_storeService = storeService;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ class UserService {
|
|||||||
final user = await _userApiRepository.getMyUser();
|
final user = await _userApiRepository.getMyUser();
|
||||||
if (user == null) return null;
|
if (user == null) return null;
|
||||||
await _storeService.put(StoreKey.currentUser, user);
|
await _storeService.put(StoreKey.currentUser, user);
|
||||||
await _isarUserRepository.update(user);
|
await _userRepository.update(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ class UserService {
|
|||||||
);
|
);
|
||||||
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
||||||
await _storeService.put(StoreKey.currentUser, updatedUser);
|
await _storeService.put(StoreKey.currentUser, updatedUser);
|
||||||
await _isarUserRepository.update(updatedUser);
|
await _userRepository.update(updatedUser);
|
||||||
return path;
|
return path;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("Failed to upload profile image", e);
|
_log.warning("Failed to upload profile image", e);
|
||||||
@@ -59,10 +59,10 @@ class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<UserDto>> getAll() async {
|
Future<List<UserDto>> getAll() async {
|
||||||
return await _isarUserRepository.getAll();
|
return await _userRepository.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteAll() {
|
Future<void> deleteAll() {
|
||||||
return _isarUserRepository.deleteAll();
|
return _userRepository.deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -554,12 +554,18 @@ class Asset {
|
|||||||
}""";
|
}""";
|
||||||
}
|
}
|
||||||
|
|
||||||
static getVisibility(AssetVisibility visibility) => switch (visibility) {
|
static getVisibility(AssetVisibility visibility) {
|
||||||
AssetVisibility.archive => AssetVisibilityEnum.archive,
|
switch (visibility) {
|
||||||
AssetVisibility.hidden => AssetVisibilityEnum.hidden,
|
case AssetVisibility.timeline:
|
||||||
AssetVisibility.locked => AssetVisibilityEnum.locked,
|
return AssetVisibilityEnum.timeline;
|
||||||
AssetVisibility.timeline || _ => AssetVisibilityEnum.timeline,
|
case AssetVisibility.archive:
|
||||||
};
|
return AssetVisibilityEnum.archive;
|
||||||
|
case AssetVisibility.hidden:
|
||||||
|
return AssetVisibilityEnum.hidden;
|
||||||
|
case AssetVisibility.locked:
|
||||||
|
return AssetVisibilityEnum.locked;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AssetType {
|
enum AssetType {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class SSLClientCertStoreVal {
|
|||||||
final Uint8List data;
|
final Uint8List data;
|
||||||
final String? password;
|
final String? password;
|
||||||
|
|
||||||
const SSLClientCertStoreVal(this.data, this.password);
|
SSLClientCertStoreVal(this.data, this.password);
|
||||||
|
|
||||||
void save() {
|
void save() {
|
||||||
final b64Str = base64Encode(data);
|
final b64Str = base64Encode(data);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class ApiRepository {
|
|||||||
|
|
||||||
Future<T> checkNull<T>(Future<T?> future) async {
|
Future<T> checkNull<T>(Future<T?> future) async {
|
||||||
final response = await future;
|
final response = await future;
|
||||||
if (response == null) throw const NoResponseDtoError();
|
if (response == null) throw NoResponseDtoError();
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/asset_media.interface.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class AssetMediaRepository {
|
class AssetMediaRepository implements IAssetMediaRepository {
|
||||||
const AssetMediaRepository();
|
const AssetMediaRepository();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Uint8List?> getThumbnail(
|
Future<Uint8List?> getThumbnail(
|
||||||
String id, {
|
String id, {
|
||||||
int quality = 80,
|
int quality = 80,
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
class IsarDeviceAssetRepository extends IsarDatabaseRepository
|
||||||
|
implements IDeviceAssetRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
|
|
||||||
const IsarDeviceAssetRepository(this._db) : super(_db);
|
const IsarDeviceAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteIds(List<String> ids) {
|
Future<void> deleteIds(List<String> ids) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.deviceAssetEntitys.deleteAllByAssetId(ids.toList());
|
await _db.deviceAssetEntitys.deleteAllByAssetId(ids.toList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<DeviceAsset>> getByIds(List<String> localIds) {
|
Future<List<DeviceAsset>> getByIds(List<String> localIds) {
|
||||||
return _db.deviceAssetEntitys
|
return _db.deviceAssetEntitys
|
||||||
.where()
|
.where()
|
||||||
@@ -22,6 +26,7 @@ class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
|||||||
.then((value) => value.map((e) => e.toModel()).toList());
|
.then((value) => value.map((e) => e.toModel()).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> updateAll(List<DeviceAsset> assetHash) {
|
Future<bool> updateAll(List<DeviceAsset> assetHash) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.deviceAssetEntitys
|
await _db.deviceAssetEntitys
|
||||||
|
|||||||
@@ -1,30 +1,36 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
||||||
as entity;
|
as entity;
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarExifRepository extends IsarDatabaseRepository {
|
class IsarExifRepository extends IsarDatabaseRepository
|
||||||
|
implements IExifInfoRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
|
|
||||||
const IsarExifRepository(this._db) : super(_db);
|
const IsarExifRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(int assetId) async {
|
Future<void> delete(int assetId) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.exifInfos.delete(assetId);
|
await _db.exifInfos.delete(assetId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAll() async {
|
Future<void> deleteAll() async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.exifInfos.clear();
|
await _db.exifInfos.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<ExifInfo?> get(int assetId) async {
|
Future<ExifInfo?> get(int assetId) async {
|
||||||
return (await _db.exifInfos.get(assetId))?.toDto();
|
return (await _db.exifInfos.get(assetId))?.toDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<ExifInfo> update(ExifInfo exifInfo) {
|
Future<ExifInfo> update(ExifInfo exifInfo) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo));
|
await _db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo));
|
||||||
@@ -32,6 +38,7 @@ class IsarExifRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos) {
|
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.exifInfos.putAll(
|
await _db.exifInfos.putAll(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||||
@@ -7,15 +8,15 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.d
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAlbumRepository {
|
||||||
class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
final Platform _platform;
|
final Platform _platform;
|
||||||
const DriftLocalAlbumRepository(this._db, {Platform? platform})
|
const DriftLocalAlbumRepository(this._db, {Platform? platform})
|
||||||
: _platform = platform ?? const LocalPlatform(),
|
: _platform = platform ?? const LocalPlatform(),
|
||||||
super(_db);
|
super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
||||||
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(String albumId) => transaction(() async {
|
Future<void> delete(String albumId) => transaction(() async {
|
||||||
// Remove all assets that are only in this particular album
|
// Remove all assets that are only in this particular album
|
||||||
// We cannot remove all assets in the album because they might be in other albums in iOS
|
// We cannot remove all assets in the album because they might be in other albums in iOS
|
||||||
@@ -70,6 +72,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.delete();
|
.delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> syncDeletes(
|
Future<void> syncDeletes(
|
||||||
String albumId,
|
String albumId,
|
||||||
Iterable<String> assetIdsToKeep,
|
Iterable<String> assetIdsToKeep,
|
||||||
@@ -98,6 +101,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
await deleteSmt.go();
|
await deleteSmt.go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> upsert(
|
Future<void> upsert(
|
||||||
LocalAlbum localAlbum, {
|
LocalAlbum localAlbum, {
|
||||||
Iterable<LocalAsset> toUpsert = const [],
|
Iterable<LocalAsset> toUpsert = const [],
|
||||||
@@ -130,6 +134,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAll(Iterable<LocalAlbum> albums) {
|
Future<void> updateAll(Iterable<LocalAlbum> albums) {
|
||||||
return _db.transaction(() async {
|
return _db.transaction(() async {
|
||||||
await _db.localAlbumEntity
|
await _db.localAlbumEntity
|
||||||
@@ -180,6 +185,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAsset>> getAssets(String albumId) {
|
Future<List<LocalAsset>> getAssets(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.select().join(
|
final query = _db.localAlbumAssetEntity.select().join(
|
||||||
[
|
[
|
||||||
@@ -196,6 +202,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<String>> getAssetIds(String albumId) {
|
Future<List<String>> getAssetIds(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.selectOnly()
|
final query = _db.localAlbumAssetEntity.selectOnly()
|
||||||
..addColumns([_db.localAlbumAssetEntity.assetId])
|
..addColumns([_db.localAlbumAssetEntity.assetId])
|
||||||
@@ -205,6 +212,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> processDelta({
|
Future<void> processDelta({
|
||||||
required List<LocalAsset> updates,
|
required List<LocalAsset> updates,
|
||||||
required List<String> deletes,
|
required List<String> deletes,
|
||||||
@@ -245,6 +253,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAsset>> getAssetsToHash(String albumId) {
|
Future<List<LocalAsset>> getAssetsToHash(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.select().join(
|
final query = _db.localAlbumAssetEntity.select().join(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
class DriftLocalAssetRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAssetRepository {
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
const DriftLocalAssetRepository(this._db) : super(_db);
|
const DriftLocalAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
||||||
if (hashes.isEmpty) {
|
if (hashes.isEmpty) {
|
||||||
return Future.value();
|
return Future.value();
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/log.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/log.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarLogRepository extends IsarDatabaseRepository {
|
class IsarLogRepository extends IsarDatabaseRepository
|
||||||
|
implements ILogRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
const IsarLogRepository(super.db) : _db = db;
|
const IsarLogRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> deleteAll() async {
|
Future<bool> deleteAll() async {
|
||||||
await transaction(() async => await _db.loggerMessages.clear());
|
await transaction(() async => await _db.loggerMessages.clear());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LogMessage>> getAll() async {
|
Future<List<LogMessage>> getAll() async {
|
||||||
final logs =
|
final logs =
|
||||||
await _db.loggerMessages.where().sortByCreatedAtDesc().findAll();
|
await _db.loggerMessages.where().sortByCreatedAtDesc().findAll();
|
||||||
return logs.map((l) => l.toDto()).toList();
|
return logs.map((l) => l.toDto()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert(LogMessage log) async {
|
Future<bool> insert(LogMessage log) async {
|
||||||
final logEntity = LoggerMessage.fromDto(log);
|
final logEntity = LoggerMessage.fromDto(log);
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
@@ -26,6 +31,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insertAll(Iterable<LogMessage> logs) async {
|
Future<bool> insertAll(Iterable<LogMessage> logs) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
final logEntities =
|
final logEntities =
|
||||||
@@ -35,6 +41,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> truncate({int limit = 250}) async {
|
Future<void> truncate({int limit = 250}) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
final count = await _db.loggerMessages.count();
|
final count = await _db.loggerMessages.count();
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class StorageRepository {
|
class StorageRepository implements IStorageRepository {
|
||||||
final _log = Logger('StorageRepository');
|
final _log = Logger('StorageRepository');
|
||||||
|
|
||||||
|
@override
|
||||||
Future<File?> getFileForAsset(LocalAsset asset) async {
|
Future<File?> getFileForAsset(LocalAsset asset) async {
|
||||||
File? file;
|
File? file;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
||||||
@@ -5,12 +6,14 @@ import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarStoreRepository extends IsarDatabaseRepository {
|
class IsarStoreRepository extends IsarDatabaseRepository
|
||||||
|
implements IStoreRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
final validStoreKeys = StoreKey.values.map((e) => e.id).toSet();
|
final validStoreKeys = StoreKey.values.map((e) => e.id).toSet();
|
||||||
|
|
||||||
IsarStoreRepository(super.db) : _db = db;
|
IsarStoreRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> deleteAll() async {
|
Future<bool> deleteAll() async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.clear();
|
await _db.storeValues.clear();
|
||||||
@@ -18,6 +21,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<StoreDto<Object>> watchAll() {
|
Stream<StoreDto<Object>> watchAll() {
|
||||||
return _db.storeValues
|
return _db.storeValues
|
||||||
.filter()
|
.filter()
|
||||||
@@ -30,10 +34,12 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete<T>(StoreKey<T> key) async {
|
Future<void> delete<T>(StoreKey<T> key) async {
|
||||||
return await transaction(() async => await _db.storeValues.delete(key.id));
|
return await transaction(() async => await _db.storeValues.delete(key.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert<T>(StoreKey<T> key, T value) async {
|
Future<bool> insert<T>(StoreKey<T> key, T value) async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.put(await _fromValue(key, value));
|
await _db.storeValues.put(await _fromValue(key, value));
|
||||||
@@ -41,6 +47,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<T?> tryGet<T>(StoreKey<T> key) async {
|
Future<T?> tryGet<T>(StoreKey<T> key) async {
|
||||||
final entity = (await _db.storeValues.get(key.id));
|
final entity = (await _db.storeValues.get(key.id));
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
@@ -49,6 +56,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
return await _toValue(key, entity);
|
return await _toValue(key, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> update<T>(StoreKey<T> key, T value) async {
|
Future<bool> update<T>(StoreKey<T> key, T value) async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.put(await _fromValue(key, value));
|
await _db.storeValues.put(await _fromValue(key, value));
|
||||||
@@ -56,6 +64,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<T?> watch<T>(StoreKey<T> key) async* {
|
Stream<T?> watch<T>(StoreKey<T> key) async* {
|
||||||
yield* _db.storeValues
|
yield* _db.storeValues
|
||||||
.watchObject(key.id, fireImmediately: true)
|
.watchObject(key.id, fireImmediately: true)
|
||||||
@@ -100,6 +109,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<StoreDto<Object>>> getAll() async {
|
Future<List<StoreDto<Object>>> getAll() async {
|
||||||
final entities = await _db.storeValues
|
final entities = await _db.storeValues
|
||||||
.filter()
|
.filter()
|
||||||
|
|||||||
@@ -3,21 +3,24 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class SyncApiRepository {
|
class SyncApiRepository implements ISyncApiRepository {
|
||||||
final Logger _logger = Logger('SyncApiRepository');
|
final Logger _logger = Logger('SyncApiRepository');
|
||||||
final ApiService _api;
|
final ApiService _api;
|
||||||
SyncApiRepository(this._api);
|
SyncApiRepository(this._api);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> ack(List<String> data) {
|
Future<void> ack(List<String> data) {
|
||||||
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
|
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> streamChanges(
|
Future<void> streamChanges(
|
||||||
Function(List<SyncEvent>, Function() abort) onData, {
|
Function(List<SyncEvent>, Function() abort) onData, {
|
||||||
int batchSize = kSyncEventBatchSize,
|
int batchSize = kSyncEventBatchSize,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
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/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.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/infrastructure/entities/partner.entity.drift.dart';
|
||||||
@@ -9,12 +10,14 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:openapi/api.dart' as api show AssetVisibility;
|
import 'package:openapi/api.dart' as api show AssetVisibility;
|
||||||
import 'package:openapi/api.dart' hide AssetVisibility;
|
import 'package:openapi/api.dart' hide AssetVisibility;
|
||||||
|
|
||||||
class SyncStreamRepository extends DriftDatabaseRepository {
|
class DriftSyncStreamRepository extends DriftDatabaseRepository
|
||||||
|
implements ISyncStreamRepository {
|
||||||
final Logger _logger = Logger('DriftSyncStreamRepository');
|
final Logger _logger = Logger('DriftSyncStreamRepository');
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
|
|
||||||
SyncStreamRepository(super.db) : _db = db;
|
DriftSyncStreamRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -31,6 +34,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
|
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -53,6 +57,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
|
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -72,6 +77,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
|
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -95,6 +101,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _deleteAssetsV1(data);
|
await _deleteAssetsV1(data);
|
||||||
@@ -104,6 +111,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetsV1(data);
|
await _updateAssetsV1(data);
|
||||||
@@ -113,6 +121,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _deleteAssetsV1(data);
|
await _deleteAssetsV1(data);
|
||||||
@@ -122,6 +131,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetsV1(data);
|
await _updateAssetsV1(data);
|
||||||
@@ -131,6 +141,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetExifV1(data);
|
await _updateAssetExifV1(data);
|
||||||
@@ -140,6 +151,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetExifV1(data);
|
await _updateAssetExifV1(data);
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ import 'dart:async';
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:stream_transform/stream_transform.dart';
|
import 'package:stream_transform/stream_transform.dart';
|
||||||
|
|
||||||
class DriftTimelineRepository extends DriftDatabaseRepository {
|
class DriftTimelineRepository extends DriftDatabaseRepository
|
||||||
|
implements ITimelineRepository {
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
|
|
||||||
const DriftTimelineRepository(super._db) : _db = _db;
|
const DriftTimelineRepository(super._db) : _db = _db;
|
||||||
@@ -26,6 +28,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
return buckets;
|
return buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<List<Bucket>> watchMainBucket(
|
Stream<List<Bucket>> watchMainBucket(
|
||||||
List<String> userIds, {
|
List<String> userIds, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
@@ -46,6 +49,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.throttle(const Duration(seconds: 3), trailing: true);
|
.throttle(const Duration(seconds: 3), trailing: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<BaseAsset>> getMainBucketAssets(
|
Future<List<BaseAsset>> getMainBucketAssets(
|
||||||
List<String> userIds, {
|
List<String> userIds, {
|
||||||
required int offset,
|
required int offset,
|
||||||
@@ -86,6 +90,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<List<Bucket>> watchLocalBucket(
|
Stream<List<Bucket>> watchLocalBucket(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
@@ -119,6 +124,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
}).watch();
|
}).watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<BaseAsset>> getLocalBucketAssets(
|
Future<List<BaseAsset>> getLocalBucketAssets(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
required int offset,
|
required int offset,
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
|
||||||
as entity;
|
as entity;
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarUserRepository extends IsarDatabaseRepository {
|
class IsarUserRepository extends IsarDatabaseRepository
|
||||||
|
implements IUserRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
const IsarUserRepository(super.db) : _db = db;
|
const IsarUserRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(List<String> ids) async {
|
Future<void> delete(List<String> ids) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.deleteAllById(ids);
|
await _db.users.deleteAllById(ids);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAll() async {
|
Future<void> deleteAll() async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.clear();
|
await _db.users.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
|
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
|
||||||
return (await _db.users
|
return (await _db.users
|
||||||
.where()
|
.where()
|
||||||
@@ -35,14 +39,17 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto?> getByUserId(String id) async {
|
Future<UserDto?> getByUserId(String id) async {
|
||||||
return (await _db.users.getById(id))?.toDto();
|
return (await _db.users.getById(id))?.toDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto?>> getByUserIds(List<String> ids) async {
|
Future<List<UserDto?>> getByUserIds(List<String> ids) async {
|
||||||
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
|
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert(UserDto user) async {
|
Future<bool> insert(UserDto user) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.put(entity.User.fromDto(user));
|
await _db.users.put(entity.User.fromDto(user));
|
||||||
@@ -50,6 +57,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto> update(UserDto user) async {
|
Future<UserDto> update(UserDto user) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.put(entity.User.fromDto(user));
|
await _db.users.put(entity.User.fromDto(user));
|
||||||
@@ -57,6 +65,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> updateAll(List<UserDto> users) async {
|
Future<bool> updateAll(List<UserDto> users) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.putAll(users.map(entity.User.fromDto).toList());
|
await _db.users.putAll(users.map(entity.User.fromDto).toList());
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class UserApiRepository extends ApiRepository {
|
class UserApiRepository extends ApiRepository implements IUserApiRepository {
|
||||||
final UsersApi _api;
|
final UsersApi _api;
|
||||||
const UserApiRepository(this._api);
|
const UserApiRepository(this._api);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto?> getMyUser() async {
|
Future<UserDto?> getMyUser() async {
|
||||||
final (adminDto, preferenceDto) =
|
final (adminDto, preferenceDto) =
|
||||||
await (_api.getMyUser(), _api.getMyPreferences()).wait;
|
await (_api.getMyUser(), _api.getMyPreferences()).wait;
|
||||||
@@ -18,6 +20,7 @@ class UserApiRepository extends ApiRepository {
|
|||||||
return UserConverter.fromAdminDto(adminDto, preferenceDto);
|
return UserConverter.fromAdminDto(adminDto, preferenceDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> createProfileImage({
|
Future<String> createProfileImage({
|
||||||
required String name,
|
required String name,
|
||||||
required Uint8List data,
|
required Uint8List data,
|
||||||
@@ -30,6 +33,7 @@ class UserApiRepository extends ApiRepository {
|
|||||||
return res.profileImagePath;
|
return res.profileImagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto>> getAll() async {
|
Future<List<UserDto>> getAll() async {
|
||||||
final dto = await checkNull(_api.searchUsers());
|
final dto = await checkNull(_api.searchUsers());
|
||||||
return dto.map(UserConverter.fromSimpleUserDto).toList();
|
return dto.map(UserConverter.fromSimpleUserDto).toList();
|
||||||
|
|||||||
16
mobile/lib/interfaces/activity_api.interface.dart
Normal file
16
mobile/lib/interfaces/activity_api.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/models/activities/activity.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IActivityApiRepository {
|
||||||
|
Future<List<Activity>> getAll(
|
||||||
|
String albumId, {
|
||||||
|
String? assetId,
|
||||||
|
});
|
||||||
|
Future<Activity> create(
|
||||||
|
String albumId,
|
||||||
|
ActivityType type, {
|
||||||
|
String? assetId,
|
||||||
|
String? comment,
|
||||||
|
});
|
||||||
|
Future<void> delete(String id);
|
||||||
|
Future<ActivityStats> getStats(String albumId, {String? assetId});
|
||||||
|
}
|
||||||
55
mobile/lib/interfaces/album.interface.dart
Normal file
55
mobile/lib/interfaces/album.interface.dart
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<Album> create(Album album);
|
||||||
|
|
||||||
|
Future<Album?> get(int id);
|
||||||
|
|
||||||
|
Future<Album?> getByName(
|
||||||
|
String name, {
|
||||||
|
bool? shared,
|
||||||
|
bool? remote,
|
||||||
|
bool? owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Album>> getAll({
|
||||||
|
bool? shared,
|
||||||
|
bool? remote,
|
||||||
|
int? ownerId,
|
||||||
|
AlbumSort? sortBy,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> update(Album album);
|
||||||
|
|
||||||
|
Future<void> delete(int albumId);
|
||||||
|
|
||||||
|
Future<void> deleteAllLocal();
|
||||||
|
|
||||||
|
Future<int> count({bool? local});
|
||||||
|
|
||||||
|
Future<void> addUsers(Album album, List<UserDto> users);
|
||||||
|
|
||||||
|
Future<void> removeUsers(Album album, List<UserDto> users);
|
||||||
|
|
||||||
|
Future<void> addAssets(Album album, List<Asset> assets);
|
||||||
|
|
||||||
|
Future<void> removeAssets(Album album, List<Asset> assets);
|
||||||
|
|
||||||
|
Future<Album> recalculateMetadata(Album album);
|
||||||
|
|
||||||
|
Future<List<Album>> search(String searchTerm, QuickFilterMode filterMode);
|
||||||
|
|
||||||
|
Stream<List<Album>> watchRemoteAlbums();
|
||||||
|
|
||||||
|
Stream<List<Album>> watchLocalAlbums();
|
||||||
|
|
||||||
|
Stream<Album?> watchAlbum(int id);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AlbumSort { remoteId, localId }
|
||||||
42
mobile/lib/interfaces/album_api.interface.dart
Normal file
42
mobile/lib/interfaces/album_api.interface.dart
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumApiRepository {
|
||||||
|
Future<Album> get(String id);
|
||||||
|
|
||||||
|
Future<List<Album>> getAll({bool? shared});
|
||||||
|
|
||||||
|
Future<Album> create(
|
||||||
|
String name, {
|
||||||
|
required Iterable<String> assetIds,
|
||||||
|
Iterable<String> sharedUserIds = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> update(
|
||||||
|
String albumId, {
|
||||||
|
String? name,
|
||||||
|
String? thumbnailAssetId,
|
||||||
|
String? description,
|
||||||
|
bool? activityEnabled,
|
||||||
|
SortOrder? sortOrder,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> delete(String albumId);
|
||||||
|
|
||||||
|
Future<({List<String> added, List<String> duplicates})> addAssets(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> assetIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<({List<String> removed, List<String> failed})> removeAssets(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> assetIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<Album> addUsers(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> userIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> removeUser(String albumId, {required String userId});
|
||||||
|
}
|
||||||
21
mobile/lib/interfaces/album_media.interface.dart
Normal file
21
mobile/lib/interfaces/album_media.interface.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumMediaRepository {
|
||||||
|
Future<List<Album>> getAll();
|
||||||
|
|
||||||
|
Future<List<String>> getAssetIds(String albumId);
|
||||||
|
|
||||||
|
Future<int> getAssetCount(String albumId);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAssets(
|
||||||
|
String albumId, {
|
||||||
|
int start = 0,
|
||||||
|
int end = 0x7fffffffffffffff,
|
||||||
|
DateTime? modifiedFrom,
|
||||||
|
DateTime? modifiedUntil,
|
||||||
|
bool orderByModificationDate = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> get(String id);
|
||||||
|
}
|
||||||
68
mobile/lib/interfaces/asset.interface.dart
Normal file
68
mobile/lib/interfaces/asset.interface.dart
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<Asset?> getByRemoteId(String id);
|
||||||
|
|
||||||
|
Future<Asset?> getByOwnerIdChecksum(int ownerId, String checksum);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAllByRemoteId(
|
||||||
|
Iterable<String> ids, {
|
||||||
|
AssetState? state,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Asset?>> getAllByOwnerIdChecksum(
|
||||||
|
List<int> ids,
|
||||||
|
List<String> checksums,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAll({
|
||||||
|
required String ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
AssetSort? sortBy,
|
||||||
|
int? limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Asset>> getAllLocal();
|
||||||
|
|
||||||
|
Future<List<Asset>> getByAlbum(
|
||||||
|
Album album, {
|
||||||
|
Iterable<String> notOwnedBy = const [],
|
||||||
|
String? ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
AssetSort? sortBy,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset> update(Asset asset);
|
||||||
|
|
||||||
|
Future<List<Asset>> updateAll(List<Asset> assets);
|
||||||
|
|
||||||
|
Future<void> deleteAllByRemoteId(List<String> ids, {AssetState? state});
|
||||||
|
|
||||||
|
Future<void> deleteByIds(List<int> ids);
|
||||||
|
|
||||||
|
Future<List<Asset>> getMatches({
|
||||||
|
required List<Asset> assets,
|
||||||
|
required String ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
int limit = 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> upsertDuplicatedAssets(Iterable<String> duplicatedAssets);
|
||||||
|
|
||||||
|
Future<List<String>> getAllDuplicatedAssetIds();
|
||||||
|
|
||||||
|
Future<List<Asset>> getStackAssets(String stackId);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
|
||||||
|
Stream<Asset?> watchAsset(int id, {bool fireImmediately = false});
|
||||||
|
|
||||||
|
Future<List<Asset>> getTrashAssets(String userId);
|
||||||
|
|
||||||
|
Future<List<Asset>> getRecentlyTakenAssets(String userId);
|
||||||
|
Future<List<Asset>> getMotionAssets(String userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AssetSort { checksum, ownerIdChecksum }
|
||||||
26
mobile/lib/interfaces/asset_api.interface.dart
Normal file
26
mobile/lib/interfaces/asset_api.interface.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetApiRepository {
|
||||||
|
// Future<Asset> get(String id);
|
||||||
|
|
||||||
|
// Future<List<Asset>> getAll();
|
||||||
|
|
||||||
|
// Future<Asset> create(Asset asset);
|
||||||
|
|
||||||
|
Future<Asset> update(
|
||||||
|
String id, {
|
||||||
|
String? description,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Future<void> delete(String id);
|
||||||
|
|
||||||
|
Future<List<Asset>> search({List<String> personIds = const []});
|
||||||
|
|
||||||
|
Future<void> updateVisibility(
|
||||||
|
List<String> list,
|
||||||
|
AssetVisibilityEnum visibility,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<String?> getAssetMIMEType(String id);
|
||||||
|
}
|
||||||
10
mobile/lib/interfaces/asset_media.interface.dart
Normal file
10
mobile/lib/interfaces/asset_media.interface.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetMediaRepository {
|
||||||
|
Future<List<String>> deleteAll(List<String> ids);
|
||||||
|
|
||||||
|
Future<Asset?> get(String id);
|
||||||
|
|
||||||
|
/// Obtaining the correct original filename of the asset
|
||||||
|
Future<String?> getOriginalFilename(String id);
|
||||||
|
}
|
||||||
11
mobile/lib/interfaces/auth.interface.dart
Normal file
11
mobile/lib/interfaces/auth.interface.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAuthRepository implements IDatabaseRepository {
|
||||||
|
Future<void> clearLocalData();
|
||||||
|
String getAccessToken();
|
||||||
|
bool getEndpointSwitchingFeature();
|
||||||
|
String? getPreferredWifiName();
|
||||||
|
String? getLocalEndpoint();
|
||||||
|
List<AuxilaryEndpoint> getExternalEndpointList();
|
||||||
|
}
|
||||||
14
mobile/lib/interfaces/auth_api.interface.dart
Normal file
14
mobile/lib/interfaces/auth_api.interface.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAuthApiRepository {
|
||||||
|
Future<LoginResponse> login(String email, String password);
|
||||||
|
|
||||||
|
Future<void> logout();
|
||||||
|
|
||||||
|
Future<void> changePassword(String newPassword);
|
||||||
|
|
||||||
|
Future<bool> unlockPinCode(String pinCode);
|
||||||
|
Future<void> lockPinCode();
|
||||||
|
|
||||||
|
Future<void> setupPinCode(String pinCode);
|
||||||
|
}
|
||||||
16
mobile/lib/interfaces/backup_album.interface.dart
Normal file
16
mobile/lib/interfaces/backup_album.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IBackupAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<List<BackupAlbum>> getAll({BackupAlbumSort? sort});
|
||||||
|
|
||||||
|
Future<List<String>> getIdsBySelection(BackupSelection backup);
|
||||||
|
|
||||||
|
Future<List<BackupAlbum>> getAllBySelection(BackupSelection backup);
|
||||||
|
|
||||||
|
Future<void> updateAll(List<BackupAlbum> backupAlbums);
|
||||||
|
|
||||||
|
Future<void> deleteAll(List<int> ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BackupAlbumSort { id }
|
||||||
6
mobile/lib/interfaces/biometric.interface.dart
Normal file
6
mobile/lib/interfaces/biometric.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IBiometricRepository {
|
||||||
|
Future<BiometricStatus> getStatus();
|
||||||
|
Future<bool> authenticate(String? message);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
15
mobile/lib/interfaces/download.interface.dart
Normal file
15
mobile/lib/interfaces/download.interface.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
|
||||||
|
abstract interface class IDownloadRepository {
|
||||||
|
void Function(TaskStatusUpdate)? onImageDownloadStatus;
|
||||||
|
void Function(TaskStatusUpdate)? onVideoDownloadStatus;
|
||||||
|
void Function(TaskStatusUpdate)? onLivePhotoDownloadStatus;
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
Future<List<TaskRecord>> getLiveVideoTasks();
|
||||||
|
Future<List<bool>> downloadAll(List<DownloadTask> tasks);
|
||||||
|
|
||||||
|
Future<bool> cancel(String id);
|
||||||
|
Future<void> deleteAllTrackingRecords();
|
||||||
|
Future<void> deleteRecordsWithIds(List<String> id);
|
||||||
|
}
|
||||||
16
mobile/lib/interfaces/etag.interface.dart
Normal file
16
mobile/lib/interfaces/etag.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/entities/etag.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IETagRepository implements IDatabaseRepository {
|
||||||
|
Future<ETag?> get(String id);
|
||||||
|
|
||||||
|
Future<ETag?> getById(String id);
|
||||||
|
|
||||||
|
Future<List<String>> getAllIds();
|
||||||
|
|
||||||
|
Future<void> upsertAll(List<ETag> etags);
|
||||||
|
|
||||||
|
Future<void> deleteByIds(List<String> ids);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
}
|
||||||
36
mobile/lib/interfaces/file_media.interface.dart
Normal file
36
mobile/lib/interfaces/file_media.interface.dart
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IFileMediaRepository {
|
||||||
|
Future<Asset?> saveImage(
|
||||||
|
Uint8List data, {
|
||||||
|
required String title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveImageWithFile(
|
||||||
|
String filePath, {
|
||||||
|
String? title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveVideo(
|
||||||
|
File file, {
|
||||||
|
required String title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveLivePhoto({
|
||||||
|
required File image,
|
||||||
|
required File video,
|
||||||
|
required String title,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> clearFileCache();
|
||||||
|
|
||||||
|
Future<void> enableBackgroundAccess();
|
||||||
|
|
||||||
|
Future<void> requestExtendedPermissions();
|
||||||
|
}
|
||||||
6
mobile/lib/interfaces/folder_api.interface.dart
Normal file
6
mobile/lib/interfaces/folder_api.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IFolderApiRepository {
|
||||||
|
Future<List<String>> getAllUniquePaths();
|
||||||
|
Future<List<Asset>> getAssetsForPath(String? path);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user