mirror of
https://github.com/immich-app/immich.git
synced 2025-12-09 09:13:08 +03:00
Compare commits
1 Commits
fix/folder
...
fix/web-no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e62071fda0 |
@@ -73,10 +73,10 @@ install_dependencies() {
|
||||
log "Installing dependencies"
|
||||
(
|
||||
cd "${IMMICH_WORKSPACE}" || exit 1
|
||||
run_cmd make ci-server
|
||||
run_cmd make ci-sdk
|
||||
run_cmd make install-server
|
||||
run_cmd make install-sdk
|
||||
run_cmd make build-sdk
|
||||
run_cmd make ci-web
|
||||
run_cmd make install-web
|
||||
)
|
||||
log ""
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ services:
|
||||
build:
|
||||
target: dev-container-server
|
||||
env_file: !reset []
|
||||
hostname: immich-dev
|
||||
environment:
|
||||
- IMMICH_SERVER_URL=http://127.0.0.1:2283/
|
||||
volumes: !override
|
||||
|
||||
@@ -6,11 +6,7 @@ design/
|
||||
docker/
|
||||
!docker/scripts
|
||||
docs/
|
||||
!docs/package.json
|
||||
!docs/package-lock.json
|
||||
e2e/
|
||||
!e2e/package.json
|
||||
!e2e/package-lock.json
|
||||
fastlane/
|
||||
machine-learning/
|
||||
misc/
|
||||
|
||||
2
.github/workflows/build-mobile.yml
vendored
2
.github/workflows/build-mobile.yml
vendored
@@ -73,7 +73,7 @@ jobs:
|
||||
cache: 'gradle'
|
||||
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
||||
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version-file: ./mobile/pubspec.yaml
|
||||
|
||||
7
.github/workflows/cli.yml
vendored
7
.github/workflows/cli.yml
vendored
@@ -38,9 +38,6 @@ jobs:
|
||||
with:
|
||||
node-version-file: './cli/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Prepare SDK
|
||||
run: npm ci --prefix ../open-api/typescript-sdk/
|
||||
- name: Build SDK
|
||||
@@ -70,7 +67,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
|
||||
- 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
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
@@ -99,7 +96,7 @@ jobs:
|
||||
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
|
||||
|
||||
- name: Build and push image
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
|
||||
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
|
||||
with:
|
||||
file: cli/Dockerfile
|
||||
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.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# 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).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- 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.
|
||||
# 📚 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
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
with:
|
||||
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
|
||||
if: always()
|
||||
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:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
||||
@@ -188,6 +188,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
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:
|
||||
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
|
||||
with:
|
||||
node-version-file: './docs/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run npm install
|
||||
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
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Fix formatting
|
||||
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: Create draft release
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
|
||||
with:
|
||||
draft: true
|
||||
tag_name: ${{ env.IMMICH_VERSION }}
|
||||
|
||||
2
.github/workflows/sdk.yml
vendored
2
.github/workflows/sdk.yml
vendored
@@ -25,8 +25,6 @@ jobs:
|
||||
with:
|
||||
node-version-file: './open-api/typescript-sdk/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
- name: Install deps
|
||||
run: npm ci
|
||||
- name: Build
|
||||
|
||||
6
.github/workflows/static_analysis.yml
vendored
6
.github/workflows/static_analysis.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
||||
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version-file: ./mobile/pubspec.yaml
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
working-directory: ./mobile
|
||||
|
||||
- name: Run DCM
|
||||
run: dcm analyze lib --fatal-style --fatal-warnings
|
||||
run: dcm analyze lib
|
||||
working-directory: ./mobile
|
||||
|
||||
zizmor:
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- 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:
|
||||
sarif_file: results.sarif
|
||||
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
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
@@ -127,8 +125,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './cli/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -174,8 +170,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './cli/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -214,8 +208,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './web/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -257,8 +249,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './web/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -292,8 +282,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './web/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm --prefix=web ci
|
||||
@@ -338,8 +326,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './e2e/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -383,8 +369,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
@@ -418,8 +402,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './e2e/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -468,8 +450,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './e2e/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run setup typescript-sdk
|
||||
run: npm ci && npm run build
|
||||
@@ -481,7 +461,7 @@ jobs:
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install chromium --only-shell
|
||||
run: npx playwright install --with-deps chromium
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- name: Docker build
|
||||
@@ -499,7 +479,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
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:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
||||
@@ -516,7 +496,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Flutter SDK
|
||||
uses: subosito/flutter-action@395322a6cded4e9ed503aebd4cc1965625f8e59a # v2.20.0
|
||||
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
|
||||
with:
|
||||
channel: 'stable'
|
||||
flutter-version-file: ./mobile/pubspec.yaml
|
||||
@@ -588,8 +568,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './.github/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Run npm install
|
||||
run: npm ci
|
||||
@@ -631,8 +609,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Install server dependencies
|
||||
run: npm --prefix=server ci
|
||||
@@ -668,7 +644,7 @@ jobs:
|
||||
contents: read
|
||||
services:
|
||||
postgres:
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:1f5583fe3397210a0fbc7f11b0cec18bacc4a99e3e8ea0548e9bd6bcf26ec37a
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
@@ -694,8 +670,6 @@ jobs:
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: './server/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
|
||||
- name: Install server dependencies
|
||||
run: npm ci
|
||||
|
||||
2
.github/workflows/weblate-lock.yml
vendored
2
.github/workflows/weblate-lock.yml
vendored
@@ -52,6 +52,6 @@ jobs:
|
||||
permissions: {}
|
||||
if: always()
|
||||
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:
|
||||
needs: ${{ toJSON(needs) }}
|
||||
|
||||
5
Makefile
5
Makefile
@@ -48,8 +48,6 @@ audit-%:
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
|
||||
install-%:
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
|
||||
ci-%:
|
||||
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) ci
|
||||
build-cli: build-sdk
|
||||
build-web: build-sdk
|
||||
build-%: install-%
|
||||
@@ -83,8 +81,7 @@ test-medium-dev:
|
||||
docker exec -it immich_server /bin/sh -c "npm run test:medium"
|
||||
|
||||
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
|
||||
install-all: $(foreach M,$(filter-out .github,$(MODULES)),install-$M) ;
|
||||
ci-all: $(foreach M,$(filter-out .github,$(MODULES)),ci-$M) ;
|
||||
install-all: $(foreach M,$(MODULES),install-$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) ;
|
||||
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",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.69",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.69",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.3",
|
||||
@@ -27,7 +27,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
@@ -54,14 +54,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.135.3",
|
||||
"version": "1.135.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.69",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
@@ -21,7 +21,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
|
||||
@@ -122,7 +122,7 @@ services:
|
||||
|
||||
database:
|
||||
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.2-pgvectors0.2.0
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
||||
@@ -63,7 +63,7 @@ services:
|
||||
|
||||
database:
|
||||
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.2-pgvectors0.2.0
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
@@ -94,7 +94,7 @@ services:
|
||||
command: ['./run.sh', '-disable-reporting']
|
||||
ports:
|
||||
- 3000:3000
|
||||
image: grafana/grafana:12.0.2-ubuntu@sha256:0512d81cdeaaff0e370a9aa66027b465d1f1f04379c3a9c801a905fabbdbc7a5
|
||||
image: grafana/grafana:12.0.1-ubuntu@sha256:65575bb9c761335e2ff30e364f21d38632e3b2e75f5f81d83cc92f44b9bbc055
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
|
||||
database:
|
||||
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.2-pgvectors0.2.0
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
|
||||
@@ -39,8 +39,8 @@ alt="Dot Env Example"
|
||||
/>
|
||||
|
||||
- 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 `UPLOAD_LOCATION` to a folder (absolute path) where media (uploaded and generated) will be stored.
|
||||
- Change `DB_DATA_LOCATION` to a folder where the database will be saved to disk.
|
||||
- Change `UPLOAD_LOCATION` to a folder where media (uploaded and generated) will be stored.
|
||||
|
||||
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",
|
||||
"url": "https://v1.135.0.archive.immich.app"
|
||||
|
||||
@@ -39,7 +39,7 @@ services:
|
||||
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
|
||||
|
||||
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
|
||||
environment:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
14
e2e/package-lock.json
generated
14
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.135.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.135.0",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
@@ -15,7 +15,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"@types/oidc-provider": "^9.0.0",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
@@ -44,7 +44,7 @@
|
||||
},
|
||||
"../cli": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.69",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
@@ -66,7 +66,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
@@ -93,14 +93,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.135.3",
|
||||
"version": "1.135.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.135.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.15.32",
|
||||
"@types/node": "^22.15.31",
|
||||
"@types/oidc-provider": "^9.0.0",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
|
||||
@@ -14,11 +14,7 @@ describe('/people', () => {
|
||||
let nameAlicePerson: PersonResponseDto;
|
||||
let nameBobPerson: PersonResponseDto;
|
||||
let nameCharliePerson: PersonResponseDto;
|
||||
let nameNullPerson4Assets: PersonResponseDto;
|
||||
let nameNullPerson3Assets: PersonResponseDto;
|
||||
let nameNullPerson1Asset: PersonResponseDto;
|
||||
let nameBillPersonFavourite: PersonResponseDto;
|
||||
let nameFreddyPersonFavourite: PersonResponseDto;
|
||||
let nameNullPerson: PersonResponseDto;
|
||||
|
||||
beforeAll(async () => {
|
||||
await utils.resetDatabase();
|
||||
@@ -31,11 +27,7 @@ describe('/people', () => {
|
||||
nameCharliePerson,
|
||||
nameBobPerson,
|
||||
nameAlicePerson,
|
||||
nameNullPerson4Assets,
|
||||
nameNullPerson3Assets,
|
||||
nameNullPerson1Asset,
|
||||
nameBillPersonFavourite,
|
||||
nameFreddyPersonFavourite,
|
||||
nameNullPerson,
|
||||
] = await Promise.all([
|
||||
utils.createPerson(admin.accessToken, {
|
||||
name: 'visible_person',
|
||||
@@ -60,26 +52,11 @@ describe('/people', () => {
|
||||
utils.createPerson(admin.accessToken, {
|
||||
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 asset2 = await utils.createAsset(admin.accessToken);
|
||||
const asset3 = await utils.createAsset(admin.accessToken);
|
||||
const asset4 = await utils.createAsset(admin.accessToken);
|
||||
|
||||
await Promise.all([
|
||||
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: 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
|
||||
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
||||
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
||||
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
||||
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
||||
// Null-named person 4 assets
|
||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson4Assets.id }),
|
||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson4Assets.id }),
|
||||
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 }),
|
||||
// Null-named person
|
||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson.id }),
|
||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson.id }), // 2 assets
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -122,19 +87,15 @@ describe('/people', () => {
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual({
|
||||
hasNextPage: false,
|
||||
total: 11,
|
||||
total: 7,
|
||||
hidden: 1,
|
||||
people: [
|
||||
expect.objectContaining({ name: 'Freddy' }),
|
||||
expect.objectContaining({ name: 'Bill' }),
|
||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||
expect.objectContaining({ name: 'Bob' }),
|
||||
expect.objectContaining({ name: 'Alice' }),
|
||||
expect.objectContaining({ name: 'Charlie' }),
|
||||
expect.objectContaining({ name: 'visible_person' }),
|
||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
||||
expect.objectContaining({ name: 'hidden_person' }), // Should really be before the null names
|
||||
expect.objectContaining({ name: 'hidden_person' }),
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -144,21 +105,17 @@ describe('/people', () => {
|
||||
|
||||
expect(status).toBe(200);
|
||||
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'
|
||||
|
||||
const people = body.people as PersonResponseDto[];
|
||||
|
||||
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
|
||||
nameBobPerson.id, // name: 'Bob', count: 2
|
||||
nameAlicePerson.id, // name: 'Alice', count: 1
|
||||
nameCharliePerson.id, // name: 'Charlie', 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);
|
||||
@@ -170,18 +127,14 @@ describe('/people', () => {
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual({
|
||||
hasNextPage: false,
|
||||
total: 11,
|
||||
total: 7,
|
||||
hidden: 1,
|
||||
people: [
|
||||
expect.objectContaining({ name: 'Freddy' }),
|
||||
expect.objectContaining({ name: 'Bill' }),
|
||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||
expect.objectContaining({ name: 'Bob' }),
|
||||
expect.objectContaining({ name: 'Alice' }),
|
||||
expect.objectContaining({ name: 'Charlie' }),
|
||||
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(body).toEqual({
|
||||
hasNextPage: true,
|
||||
total: 11,
|
||||
total: 7,
|
||||
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.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', () => {
|
||||
|
||||
@@ -464,6 +464,7 @@
|
||||
"assets": "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_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_count": "{count, plural, one {# asset} other {# assets}}",
|
||||
"assets_deleted_permanently": "{count} asset(s) deleted permanently",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
|
||||
@@ -59,7 +59,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256: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 \
|
||||
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||
@@ -68,11 +68,11 @@ RUN if [ "$DEVICE" = "rocm" ]; then \
|
||||
uv pip install /opt/onnxruntime_rocm-*.whl; \
|
||||
fi
|
||||
|
||||
FROM python:3.11-slim-bookworm@sha256:9e1912aab0a30bbd9488eb79063f68f42a68ab0946cbe98fecf197fe5b085506 AS prod-cpu
|
||||
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-cpu
|
||||
|
||||
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
|
||||
|
||||
FROM python:3.11-slim-bookworm@sha256:9e1912aab0a30bbd9488eb79063f68f42a68ab0946cbe98fecf197fe5b085506 AS prod-openvino
|
||||
FROM python:3.11-slim-bookworm@sha256:7a3ed1226224bcc1fe5443262363d42f48cf832a540c1836ba8ccbeaadf8637c AS prod-openvino
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install --no-install-recommends -yqq ocl-icd-libopencl1 wget && \
|
||||
|
||||
@@ -244,6 +244,7 @@ async def load(model: InferenceModel) -> InferenceModel:
|
||||
|
||||
async def idle_shutdown_task() -> None:
|
||||
while True:
|
||||
log.debug("Checking for inactivity...")
|
||||
if (
|
||||
last_called is not None
|
||||
and not active_requests
|
||||
|
||||
141
machine-learning/uv.lock
generated
141
machine-learning/uv.lock
generated
@@ -517,16 +517,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.115.13"
|
||||
version = "0.115.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "starlette" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
@@ -900,7 +900,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "huggingface-hub"
|
||||
version = "0.33.0"
|
||||
version = "0.32.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "filelock" },
|
||||
@@ -912,9 +912,9 @@ dependencies = [
|
||||
{ name = "tqdm" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/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 = [
|
||||
{ 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]]
|
||||
@@ -1225,7 +1225,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "locust"
|
||||
version = "2.37.11"
|
||||
version = "2.37.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "configargparse" },
|
||||
@@ -1245,14 +1245,14 @@ dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
name = "locust-cloud"
|
||||
version = "1.24.2"
|
||||
version = "1.23.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "configargparse" },
|
||||
@@ -1262,9 +1262,9 @@ dependencies = [
|
||||
{ name = "python-socketio", extra = ["client"] },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
@@ -1415,7 +1415,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.16.1"
|
||||
version = "1.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
@@ -1423,33 +1423,33 @@ dependencies = [
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ 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 = [
|
||||
{ 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/64/5e/a0485f0608a3d67029d3d73cec209278b025e3493a3acfda3ef3a88540fd/mypy-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7909541fef256527e5ee9c0a7e2aeed78b6cda72ba44298d1334fe7881b05c5c", size = 10967416, upload-time = "2025-05-29T13:34:17.783Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/53/5837c221f74c0d53a4bfc3003296f8179c3a2a7f336d7de7bbafbe96b688/mypy-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e71d6f0090c2256c713ed3d52711d01859c82608b5d68d4fa01a3fe30df95571", size = 10087654, upload-time = "2025-05-29T13:32:37.878Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/59/5fd2400352c3093bed4c09017fe671d26bc5bb7e6ef2d4bf85f2a2488104/mypy-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:936ccfdd749af4766be824268bfe22d1db9eb2f34a3ea1d00ffbe5b5265f5491", size = 11875192, upload-time = "2025-05-29T13:34:54.281Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/3e/4bfec74663a64c2012f3e278dbc29ffe82b121bc551758590d1b6449ec0c/mypy-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4086883a73166631307fdd330c4a9080ce24913d4f4c5ec596c601b3a4bdd777", size = 12612939, upload-time = "2025-05-29T13:33:14.766Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/1f/fecbe3dcba4bf2ca34c26ca016383a9676711907f8db4da8354925cbb08f/mypy-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:feec38097f71797da0231997e0de3a58108c51845399669ebc532c815f93866b", size = 12874719, upload-time = "2025-05-29T13:21:52.09Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/51/c2d280601cd816c43dfa512a759270d5a5ef638d7ac9bea9134c8305a12f/mypy-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:09a8da6a0ee9a9770b8ff61b39c0bb07971cda90e7297f4213741b48a0cc8d93", size = 9487053, upload-time = "2025-05-29T13:33:29.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/c4/ff2f79db7075c274fe85b5fff8797d29c6b61b8854c39e3b7feb556aa377/mypy-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9f826aaa7ff8443bac6a494cf743f591488ea940dd360e7dd330e30dd772a5ab", size = 10884498, upload-time = "2025-05-29T13:18:54.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/07/12198e83006235f10f6a7808917376b5d6240a2fd5dce740fe5d2ebf3247/mypy-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82d056e6faa508501af333a6af192c700b33e15865bda49611e3d7d8358ebea2", size = 10011755, upload-time = "2025-05-29T13:34:00.851Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/9b/5fd5801a72b5d6fb6ec0105ea1d0e01ab2d4971893076e558d4b6d6b5f80/mypy-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:089bedc02307c2548eb51f426e085546db1fa7dd87fbb7c9fa561575cf6eb1ff", size = 11800138, upload-time = "2025-05-29T13:32:55.082Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/81/a117441ea5dfc3746431e51d78a4aca569c677aa225bca2cc05a7c239b61/mypy-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6a2322896003ba66bbd1318c10d3afdfe24e78ef12ea10e2acd985e9d684a666", size = 12533156, upload-time = "2025-05-29T13:19:12.963Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/38/88ec57c6c86014d3f06251e00f397b5a7daa6888884d0abf187e4f5f587f/mypy-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:021a68568082c5b36e977d54e8f1de978baf401a33884ffcea09bd8e88a98f4c", size = 12742426, upload-time = "2025-05-29T13:20:22.72Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/53/7e9d528433d56e6f6f77ccf24af6ce570986c2d98a5839e4c2009ef47283/mypy-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:54066fed302d83bf5128632d05b4ec68412e1f03ef2c300434057d66866cea4b", size = 9478319, upload-time = "2025-05-29T13:21:17.582Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/cf/158e5055e60ca2be23aec54a3010f89dcffd788732634b344fc9cb1e85a0/mypy-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5436d11e89a3ad16ce8afe752f0f373ae9620841c50883dc96f8b8805620b13", size = 11062927, upload-time = "2025-05-29T13:35:52.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/34/cfff7a56be1609f5d10ef386342ce3494158e4d506516890142007e6472c/mypy-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f2622af30bf01d8fc36466231bdd203d120d7a599a6d88fb22bdcb9dbff84090", size = 10083082, upload-time = "2025-05-29T13:35:33.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/7f/7242062ec6288c33d8ad89574df87c3903d394870e5e6ba1699317a65075/mypy-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d045d33c284e10a038f5e29faca055b90eee87da3fc63b8889085744ebabb5a1", size = 11828306, upload-time = "2025-05-29T13:21:02.164Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/5f/b392f7b4f659f5b619ce5994c5c43caab3d80df2296ae54fa888b3d17f5a/mypy-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4968f14f44c62e2ec4a038c8797a87315be8df7740dc3ee8d3bfe1c6bf5dba8", size = 12702764, upload-time = "2025-05-29T13:20:42.826Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/c0/7646ef3a00fa39ac9bc0938626d9ff29d19d733011be929cfea59d82d136/mypy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb14a4a871bb8efb1e4a50360d4e3c8d6c601e7a31028a2c79f9bb659b63d730", size = 12896233, upload-time = "2025-05-29T13:18:37.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/38/52f4b808b3fef7f0ef840ee8ff6ce5b5d77381e65425758d515cdd4f5bb5/mypy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd4e1ebe126152a7bbaa4daedd781c90c8f9643c79b9748caa270ad542f12bec", size = 9565547, upload-time = "2025-05-29T13:20:02.836Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/9c/ca03bdbefbaa03b264b9318a98950a9c683e06472226b55472f96ebbc53d/mypy-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e056237c89f1587a3be1a3a70a06a698d25e2479b9a2f57325ddaaffc3567b", size = 11059753, upload-time = "2025-05-29T13:18:18.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/92/79a969b8302cfe316027c88f7dc6fee70129490a370b3f6eb11d777749d0/mypy-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b07e107affb9ee6ce1f342c07f51552d126c32cd62955f59a7db94a51ad12c0", size = 10073338, upload-time = "2025-05-29T13:19:48.079Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/9b/a943f09319167da0552d5cd722104096a9c99270719b1afeea60d11610aa/mypy-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6fb60cbd85dc65d4d63d37cb5c86f4e3a301ec605f606ae3a9173e5cf34997b", size = 11827764, upload-time = "2025-05-29T13:46:04.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/64/ff75e71c65a0cb6ee737287c7913ea155845a556c64144c65b811afdb9c7/mypy-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7e32297a437cc915599e0578fa6bc68ae6a8dc059c9e009c628e1c47f91495d", size = 12701356, upload-time = "2025-05-29T13:35:13.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/ad/0e93c18987a1182c350f7a5fab70550852f9fabe30ecb63bfbe51b602074/mypy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:afe420c9380ccec31e744e8baff0d406c846683681025db3531b32db56962d52", size = 12900745, upload-time = "2025-05-29T13:17:24.409Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/5d/036c278d7a013e97e33f08c047fe5583ab4f1fc47c9a49f985f1cdd2a2d7/mypy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:55f9076c6ce55dd3f8cd0c6fff26a008ca8e5131b89d5ba6d86bd3f47e736eeb", size = 9572200, upload-time = "2025-05-29T13:33:44.92Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/a3/6ed10530dec8e0fdc890d81361260c9ef1f5e5c217ad8c9b21ecb2b8366b/mypy-1.16.0-py3-none-any.whl", hash = "sha256:29e1499864a3888bca5c1542f2d7232c6e586295183320caa95758fc84034031", size = 2265773, upload-time = "2025-05-29T13:35:18.762Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1834,7 +1834,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.11.7"
|
||||
version = "2.11.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
@@ -1842,9 +1842,9 @@ dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
@@ -1977,7 +1977,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.4.1"
|
||||
version = "8.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
@@ -1988,9 +1988,9 @@ dependencies = [
|
||||
{ name = "pygments" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
@@ -2007,16 +2007,15 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "6.2.1"
|
||||
version = "6.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "coverage", extra = ["toml"] },
|
||||
{ name = "pluggy" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
@@ -2304,27 +2303,27 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.12.0"
|
||||
version = "0.11.13"
|
||||
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 = [
|
||||
{ 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2559,14 +2558,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.32.4.20250611"
|
||||
version = "2.32.0.20250602"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
|
||||
@@ -146,7 +146,6 @@ dart_code_metrics:
|
||||
# - no-empty-block
|
||||
# - no-equal-then-else
|
||||
# - prefer-correct-test-file-name
|
||||
- prefer-const-border-radius
|
||||
# - prefer-match-file-name
|
||||
# - prefer-return-await
|
||||
# - avoid-self-assignment
|
||||
@@ -291,8 +290,7 @@ dart_code_metrics:
|
||||
# Style
|
||||
# - prefer-trailing-comma
|
||||
# - unnecessary-trailing-comma
|
||||
- prefer-declaring-const-constructor
|
||||
# - prefer-declaring-const-constructor
|
||||
# - prefer-single-widget-per-file
|
||||
- prefer-switch-expression
|
||||
# - prefer-prefixed-global-constants
|
||||
# - prefer-correct-callback-field-name
|
||||
|
||||
@@ -90,35 +90,6 @@
|
||||
<data android:mimeType="video/*" />
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 204,
|
||||
"android.injected.version.name" => "1.135.3",
|
||||
"android.injected.version.code" => 201,
|
||||
"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')
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'general_helper.dart';
|
||||
class ImmichTestLoginHelper {
|
||||
final WidgetTester tester;
|
||||
|
||||
const ImmichTestLoginHelper(this.tester);
|
||||
ImmichTestLoginHelper(this.tester);
|
||||
|
||||
Future<void> waitForLoginScreen() async {
|
||||
await pumpUntilFound(tester, find.text("Login"));
|
||||
@@ -60,11 +60,11 @@ class ImmichTestLoginHelper {
|
||||
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()));
|
||||
}
|
||||
|
||||
Future<void> assertLoginFailed() async {
|
||||
Future<void> assertLoginFailed({int timeoutSeconds = 15}) async {
|
||||
await pumpUntilFound(tester, find.text("login_form_failed_login".tr()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -793,7 +793,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -823,7 +823,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -857,7 +857,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -865,7 +865,7 @@
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -900,7 +900,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -908,7 +908,7 @@
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -940,7 +940,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -948,7 +948,7 @@
|
||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -979,7 +979,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
@@ -1023,7 +1023,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
@@ -1064,7 +1064,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 209;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.135.1</string>
|
||||
<string>1.135.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
@@ -86,26 +86,14 @@
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Share Extension</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
</array>
|
||||
</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>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>210</string>
|
||||
<string>209</string>
|
||||
<key>FLTEnableImpeller</key>
|
||||
<true />
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
@@ -127,13 +115,11 @@
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_googlecast._tcp</string>
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
<string>_googlecast._tcp</string>
|
||||
<string>_CC1AD845._googlecast._tcp</string>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>We require this permission to access the local WiFi name for background upload mechanism</string>
|
||||
<key>NSLocationUsageDescription</key>
|
||||
@@ -180,8 +166,7 @@
|
||||
<true />
|
||||
<key>io.flutter.embedded_views_preview</key>
|
||||
<true />
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>We need local network permission to connect to the local server using IP address and
|
||||
allow the casting feature to work</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||
</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">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:my.immich.app</string>
|
||||
</array>
|
||||
<key>com.apple.developer.networking.wifi-info</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<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>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
|
||||
@@ -24,11 +24,27 @@ struct ImageEntry: TimelineEntry {
|
||||
struct ImmichWidgetView: View {
|
||||
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 {
|
||||
if entry.image == nil {
|
||||
VStack {
|
||||
Image("LaunchImage")
|
||||
Text(entry.error?.errorDescription ?? "")
|
||||
Text(getErrorText(entry.error))
|
||||
.minimumScaleFactor(0.25)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
@@ -8,32 +8,6 @@ enum WidgetError: Error {
|
||||
case unknown
|
||||
case albumNotFound
|
||||
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 {
|
||||
@@ -172,7 +146,7 @@ class ImmichAPI {
|
||||
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 assetEndpoint = "/assets/" + asset.id + "/thumbnail"
|
||||
|
||||
@@ -183,24 +157,16 @@ class ImmichAPI {
|
||||
params: thumbnailParams
|
||||
)
|
||||
else {
|
||||
throw .invalidURL
|
||||
}
|
||||
|
||||
guard let imageSource = CGImageSourceCreateWithURL(fetchURL as CFURL, nil) else {
|
||||
throw .invalidURL
|
||||
throw URLError(.badURL)
|
||||
}
|
||||
|
||||
let decodeOptions: [NSString: Any] = [
|
||||
kCGImageSourceCreateThumbnailFromImageAlways: true,
|
||||
kCGImageSourceThumbnailMaxPixelSize: 400,
|
||||
kCGImageSourceCreateThumbnailWithTransform: true
|
||||
]
|
||||
|
||||
guard let thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, decodeOptions as CFDictionary) else {
|
||||
throw .fetchFailed
|
||||
let (data, _) = try await URLSession.shared.data(from: fetchURL)
|
||||
|
||||
guard let img = UIImage(data: data) else {
|
||||
throw URLError(.badServerResponse)
|
||||
}
|
||||
|
||||
return UIImage(cgImage: thumbnail)
|
||||
return img
|
||||
}
|
||||
|
||||
func fetchAlbums() async throws -> [Album] {
|
||||
|
||||
@@ -43,7 +43,7 @@ struct RandomConfigurationAppIntent: WidgetConfigurationIntent {
|
||||
"Choose an album to show images from"
|
||||
}
|
||||
|
||||
@Parameter(title: "Album")
|
||||
@Parameter(title: "Album", default: NO_ALBUM)
|
||||
var album: Album?
|
||||
|
||||
@Parameter(title: "Show Album Name", default: false)
|
||||
|
||||
@@ -22,7 +22,7 @@ platform :ios do
|
||||
path: "./Runner.xcodeproj",
|
||||
)
|
||||
increment_version_number(
|
||||
version_number: "1.135.3"
|
||||
version_number: "1.135.0"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
||||
@@ -10,5 +10,3 @@ enum TextSearchType {
|
||||
}
|
||||
|
||||
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
||||
|
||||
enum SortUserBy { id }
|
||||
|
||||
@@ -4,8 +4,6 @@ sealed class ImmichErrors {
|
||||
}
|
||||
|
||||
class NoResponseDtoError extends ImmichErrors implements Exception {
|
||||
const NoResponseDtoError();
|
||||
|
||||
@override
|
||||
String toString() => "Response Dto is null";
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ const Map<String, Locale> locales = {
|
||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
||||
'Chinese Traditional (zh_TW)':
|
||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||
'Croatian (hr)': Locale('hr'),
|
||||
'Czech (cs)': Locale('cs'),
|
||||
'Danish (da)': Locale('da'),
|
||||
'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 '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/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/presentation/pages/dev/dev_logger.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
@@ -12,16 +12,16 @@ import 'package:logging/logging.dart';
|
||||
class HashService {
|
||||
final int batchSizeLimit;
|
||||
final int batchFileLimit;
|
||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
||||
final DriftLocalAssetRepository _localAssetRepository;
|
||||
final StorageRepository _storageRepository;
|
||||
final ILocalAlbumRepository _localAlbumRepository;
|
||||
final ILocalAssetRepository _localAssetRepository;
|
||||
final IStorageRepository _storageRepository;
|
||||
final NativeSyncApi _nativeSyncApi;
|
||||
final _log = Logger('HashService');
|
||||
|
||||
HashService({
|
||||
required DriftLocalAlbumRepository localAlbumRepository,
|
||||
required DriftLocalAssetRepository localAssetRepository,
|
||||
required StorageRepository storageRepository,
|
||||
required ILocalAlbumRepository localAlbumRepository,
|
||||
required ILocalAssetRepository localAssetRepository,
|
||||
required IStorageRepository storageRepository,
|
||||
required NativeSyncApi nativeSyncApi,
|
||||
this.batchSizeLimit = kBatchHashSizeLimit,
|
||||
this.batchFileLimit = kBatchHashFileLimit,
|
||||
|
||||
@@ -2,11 +2,11 @@ import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.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/local_album.model.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||
import 'package:immich_mobile/utils/diff.dart';
|
||||
@@ -14,14 +14,14 @@ import 'package:logging/logging.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
class LocalSyncService {
|
||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
||||
final ILocalAlbumRepository _localAlbumRepository;
|
||||
final NativeSyncApi _nativeSyncApi;
|
||||
final Platform _platform;
|
||||
final StoreService _storeService;
|
||||
final Logger _log = Logger("DeviceSyncService");
|
||||
|
||||
LocalSyncService({
|
||||
required DriftLocalAlbumRepository localAlbumRepository,
|
||||
required ILocalAlbumRepository localAlbumRepository,
|
||||
required NativeSyncApi nativeSyncApi,
|
||||
required StoreService storeService,
|
||||
Platform? platform,
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.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/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';
|
||||
|
||||
/// 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
|
||||
/// via [IStoreRepository]
|
||||
class LogService {
|
||||
final IsarLogRepository _logRepository;
|
||||
final IsarStoreRepository _storeRepository;
|
||||
final ILogRepository _logRepository;
|
||||
final IStoreRepository _storeRepository;
|
||||
|
||||
final List<LogMessage> _msgBuffer = [];
|
||||
|
||||
@@ -37,8 +37,8 @@ class LogService {
|
||||
}
|
||||
|
||||
static Future<LogService> init({
|
||||
required IsarLogRepository logRepository,
|
||||
required IsarStoreRepository storeRepository,
|
||||
required ILogRepository logRepository,
|
||||
required IStoreRepository storeRepository,
|
||||
bool shouldBuffer = true,
|
||||
}) async {
|
||||
_instance ??= await create(
|
||||
@@ -50,8 +50,8 @@ class LogService {
|
||||
}
|
||||
|
||||
static Future<LogService> create({
|
||||
required IsarLogRepository logRepository,
|
||||
required IsarStoreRepository storeRepository,
|
||||
required ILogRepository logRepository,
|
||||
required IStoreRepository storeRepository,
|
||||
bool shouldBuffer = true,
|
||||
}) async {
|
||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
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/infrastructure/repositories/store.repository.dart';
|
||||
|
||||
/// Provides access to a persistent key-value store with an in-memory cache.
|
||||
/// Listens for repository changes to keep the cache updated.
|
||||
class StoreService {
|
||||
final IsarStoreRepository _storeRepository;
|
||||
final IStoreRepository _storeRepository;
|
||||
|
||||
/// In-memory cache. Keys are [StoreKey.id]
|
||||
final Map<int, Object?> _cache = {};
|
||||
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
||||
|
||||
StoreService._({required IsarStoreRepository storeRepository})
|
||||
StoreService._({required IStoreRepository storeRepository})
|
||||
: _storeRepository = storeRepository;
|
||||
|
||||
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
||||
@@ -26,14 +26,14 @@ class StoreService {
|
||||
|
||||
// TODO: Replace the implementation with the one from create after removing the typedef
|
||||
static Future<StoreService> init({
|
||||
required IsarStoreRepository storeRepository,
|
||||
required IStoreRepository storeRepository,
|
||||
}) async {
|
||||
_instance ??= await create(storeRepository: storeRepository);
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
static Future<StoreService> create({
|
||||
required IsarStoreRepository storeRepository,
|
||||
required IStoreRepository storeRepository,
|
||||
}) async {
|
||||
final instance = StoreService._(storeRepository: storeRepository);
|
||||
await instance._populateCache();
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
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/infrastructure/repositories/sync_api.repository.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
class SyncStreamService {
|
||||
final Logger _logger = Logger('SyncStreamService');
|
||||
|
||||
final SyncApiRepository _syncApiRepository;
|
||||
final SyncStreamRepository _syncStreamRepository;
|
||||
final ISyncApiRepository _syncApiRepository;
|
||||
final ISyncStreamRepository _syncStreamRepository;
|
||||
final bool Function()? _cancelChecker;
|
||||
|
||||
SyncStreamService({
|
||||
required SyncApiRepository syncApiRepository,
|
||||
required SyncStreamRepository syncStreamRepository,
|
||||
required ISyncApiRepository syncApiRepository,
|
||||
required ISyncStreamRepository syncStreamRepository,
|
||||
bool Function()? cancelChecker,
|
||||
}) : _syncApiRepository = syncApiRepository,
|
||||
_syncStreamRepository = syncStreamRepository,
|
||||
|
||||
@@ -3,11 +3,11 @@ import 'dart:math' as math;
|
||||
|
||||
import 'package:collection/collection.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/setting.model.dart';
|
||||
import 'package:immich_mobile/domain/models/timeline.model.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';
|
||||
|
||||
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
||||
@@ -18,11 +18,11 @@ typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
||||
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
||||
|
||||
class TimelineFactory {
|
||||
final DriftTimelineRepository _timelineRepository;
|
||||
final ITimelineRepository _timelineRepository;
|
||||
final SettingsService _settingsService;
|
||||
|
||||
const TimelineFactory({
|
||||
required DriftTimelineRepository timelineRepository,
|
||||
required ITimelineRepository timelineRepository,
|
||||
required SettingsService settingsService,
|
||||
}) : _timelineRepository = timelineRepository,
|
||||
_settingsService = settingsService;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import 'dart:async';
|
||||
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/user.model.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';
|
||||
|
||||
class UserService {
|
||||
final Logger _log = Logger("UserService");
|
||||
final IsarUserRepository _isarUserRepository;
|
||||
final UserApiRepository _userApiRepository;
|
||||
final IUserRepository _userRepository;
|
||||
final IUserApiRepository _userApiRepository;
|
||||
final StoreService _storeService;
|
||||
|
||||
UserService({
|
||||
required IsarUserRepository isarUserRepository,
|
||||
required UserApiRepository userApiRepository,
|
||||
required IUserRepository userRepository,
|
||||
required IUserApiRepository userApiRepository,
|
||||
required StoreService storeService,
|
||||
}) : _isarUserRepository = isarUserRepository,
|
||||
}) : _userRepository = userRepository,
|
||||
_userApiRepository = userApiRepository,
|
||||
_storeService = storeService;
|
||||
|
||||
@@ -38,7 +38,7 @@ class UserService {
|
||||
final user = await _userApiRepository.getMyUser();
|
||||
if (user == null) return null;
|
||||
await _storeService.put(StoreKey.currentUser, user);
|
||||
await _isarUserRepository.update(user);
|
||||
await _userRepository.update(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class UserService {
|
||||
);
|
||||
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
||||
await _storeService.put(StoreKey.currentUser, updatedUser);
|
||||
await _isarUserRepository.update(updatedUser);
|
||||
await _userRepository.update(updatedUser);
|
||||
return path;
|
||||
} catch (e) {
|
||||
_log.warning("Failed to upload profile image", e);
|
||||
@@ -59,10 +59,10 @@ class UserService {
|
||||
}
|
||||
|
||||
Future<List<UserDto>> getAll() async {
|
||||
return await _isarUserRepository.getAll();
|
||||
return await _userRepository.getAll();
|
||||
}
|
||||
|
||||
Future<void> deleteAll() {
|
||||
return _isarUserRepository.deleteAll();
|
||||
return _userRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,12 +554,18 @@ class Asset {
|
||||
}""";
|
||||
}
|
||||
|
||||
static getVisibility(AssetVisibility visibility) => switch (visibility) {
|
||||
AssetVisibility.archive => AssetVisibilityEnum.archive,
|
||||
AssetVisibility.hidden => AssetVisibilityEnum.hidden,
|
||||
AssetVisibility.locked => AssetVisibilityEnum.locked,
|
||||
AssetVisibility.timeline || _ => AssetVisibilityEnum.timeline,
|
||||
};
|
||||
static getVisibility(AssetVisibility visibility) {
|
||||
switch (visibility) {
|
||||
case AssetVisibility.timeline:
|
||||
return AssetVisibilityEnum.timeline;
|
||||
case AssetVisibility.archive:
|
||||
return AssetVisibilityEnum.archive;
|
||||
case AssetVisibility.hidden:
|
||||
return AssetVisibilityEnum.hidden;
|
||||
case AssetVisibility.locked:
|
||||
return AssetVisibilityEnum.locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AssetType {
|
||||
|
||||
@@ -11,7 +11,7 @@ class SSLClientCertStoreVal {
|
||||
final Uint8List data;
|
||||
final String? password;
|
||||
|
||||
const SSLClientCertStoreVal(this.data, this.password);
|
||||
SSLClientCertStoreVal(this.data, this.password);
|
||||
|
||||
void save() {
|
||||
final b64Str = base64Encode(data);
|
||||
|
||||
@@ -5,7 +5,7 @@ class ApiRepository {
|
||||
|
||||
Future<T> checkNull<T>(Future<T?> future) async {
|
||||
final response = await future;
|
||||
if (response == null) throw const NoResponseDtoError();
|
||||
if (response == null) throw NoResponseDtoError();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:immich_mobile/domain/interfaces/asset_media.interface.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
|
||||
class AssetMediaRepository {
|
||||
class AssetMediaRepository implements IAssetMediaRepository {
|
||||
const AssetMediaRepository();
|
||||
|
||||
@override
|
||||
Future<Uint8List?> getThumbnail(
|
||||
String id, {
|
||||
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/infrastructure/entities/device_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
||||
class IsarDeviceAssetRepository extends IsarDatabaseRepository
|
||||
implements IDeviceAssetRepository {
|
||||
final Isar _db;
|
||||
|
||||
const IsarDeviceAssetRepository(this._db) : super(_db);
|
||||
|
||||
@override
|
||||
Future<void> deleteIds(List<String> ids) {
|
||||
return transaction(() async {
|
||||
await _db.deviceAssetEntitys.deleteAllByAssetId(ids.toList());
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<DeviceAsset>> getByIds(List<String> localIds) {
|
||||
return _db.deviceAssetEntitys
|
||||
.where()
|
||||
@@ -22,6 +26,7 @@ class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
||||
.then((value) => value.map((e) => e.toModel()).toList());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> updateAll(List<DeviceAsset> assetHash) {
|
||||
return transaction(() async {
|
||||
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/infrastructure/entities/exif.entity.dart'
|
||||
as entity;
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class IsarExifRepository extends IsarDatabaseRepository {
|
||||
class IsarExifRepository extends IsarDatabaseRepository
|
||||
implements IExifInfoRepository {
|
||||
final Isar _db;
|
||||
|
||||
const IsarExifRepository(this._db) : super(_db);
|
||||
|
||||
@override
|
||||
Future<void> delete(int assetId) async {
|
||||
await transaction(() async {
|
||||
await _db.exifInfos.delete(assetId);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteAll() async {
|
||||
await transaction(() async {
|
||||
await _db.exifInfos.clear();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExifInfo?> get(int assetId) async {
|
||||
return (await _db.exifInfos.get(assetId))?.toDto();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExifInfo> update(ExifInfo exifInfo) {
|
||||
return transaction(() async {
|
||||
await _db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo));
|
||||
@@ -32,6 +38,7 @@ class IsarExifRepository extends IsarDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos) {
|
||||
return transaction(() async {
|
||||
await _db.exifInfos.putAll(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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/local_album.model.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:platform/platform.dart';
|
||||
|
||||
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
||||
|
||||
class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||
implements ILocalAlbumRepository {
|
||||
final Drift _db;
|
||||
final Platform _platform;
|
||||
const DriftLocalAlbumRepository(this._db, {Platform? platform})
|
||||
: _platform = platform ?? const LocalPlatform(),
|
||||
super(_db);
|
||||
|
||||
@override
|
||||
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
||||
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
||||
|
||||
@@ -55,6 +56,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> delete(String albumId) => transaction(() async {
|
||||
// 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
|
||||
@@ -70,6 +72,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
.delete();
|
||||
});
|
||||
|
||||
@override
|
||||
Future<void> syncDeletes(
|
||||
String albumId,
|
||||
Iterable<String> assetIdsToKeep,
|
||||
@@ -98,6 +101,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
await deleteSmt.go();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> upsert(
|
||||
LocalAlbum localAlbum, {
|
||||
Iterable<LocalAsset> toUpsert = const [],
|
||||
@@ -130,6 +134,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAll(Iterable<LocalAlbum> albums) {
|
||||
return _db.transaction(() async {
|
||||
await _db.localAlbumEntity
|
||||
@@ -180,6 +185,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LocalAsset>> getAssets(String albumId) {
|
||||
final query = _db.localAlbumAssetEntity.select().join(
|
||||
[
|
||||
@@ -196,6 +202,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getAssetIds(String albumId) {
|
||||
final query = _db.localAlbumAssetEntity.selectOnly()
|
||||
..addColumns([_db.localAlbumAssetEntity.assetId])
|
||||
@@ -205,6 +212,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> processDelta({
|
||||
required List<LocalAsset> updates,
|
||||
required List<String> deletes,
|
||||
@@ -245,6 +253,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LocalAsset>> getAssetsToHash(String albumId) {
|
||||
final query = _db.localAlbumAssetEntity.select().join(
|
||||
[
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
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/infrastructure/entities/local_asset.entity.drift.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
|
||||
class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
||||
class DriftLocalAssetRepository extends DriftDatabaseRepository
|
||||
implements ILocalAssetRepository {
|
||||
final Drift _db;
|
||||
const DriftLocalAssetRepository(this._db) : super(_db);
|
||||
|
||||
@override
|
||||
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
||||
if (hashes.isEmpty) {
|
||||
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/infrastructure/entities/log.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class IsarLogRepository extends IsarDatabaseRepository {
|
||||
class IsarLogRepository extends IsarDatabaseRepository
|
||||
implements ILogRepository {
|
||||
final Isar _db;
|
||||
const IsarLogRepository(super.db) : _db = db;
|
||||
|
||||
@override
|
||||
Future<bool> deleteAll() async {
|
||||
await transaction(() async => await _db.loggerMessages.clear());
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<LogMessage>> getAll() async {
|
||||
final logs =
|
||||
await _db.loggerMessages.where().sortByCreatedAtDesc().findAll();
|
||||
return logs.map((l) => l.toDto()).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> insert(LogMessage log) async {
|
||||
final logEntity = LoggerMessage.fromDto(log);
|
||||
await transaction(() async {
|
||||
@@ -26,6 +31,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> insertAll(Iterable<LogMessage> logs) async {
|
||||
await transaction(() async {
|
||||
final logEntities =
|
||||
@@ -35,6 +41,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> truncate({int limit = 250}) async {
|
||||
await transaction(() async {
|
||||
final count = await _db.loggerMessages.count();
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
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:logging/logging.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
|
||||
class StorageRepository {
|
||||
class StorageRepository implements IStorageRepository {
|
||||
final _log = Logger('StorageRepository');
|
||||
|
||||
@override
|
||||
Future<File?> getFileForAsset(LocalAsset asset) async {
|
||||
File? file;
|
||||
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/user.model.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:isar/isar.dart';
|
||||
|
||||
class IsarStoreRepository extends IsarDatabaseRepository {
|
||||
class IsarStoreRepository extends IsarDatabaseRepository
|
||||
implements IStoreRepository {
|
||||
final Isar _db;
|
||||
final validStoreKeys = StoreKey.values.map((e) => e.id).toSet();
|
||||
|
||||
IsarStoreRepository(super.db) : _db = db;
|
||||
|
||||
@override
|
||||
Future<bool> deleteAll() async {
|
||||
return await transaction(() async {
|
||||
await _db.storeValues.clear();
|
||||
@@ -18,6 +21,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<StoreDto<Object>> watchAll() {
|
||||
return _db.storeValues
|
||||
.filter()
|
||||
@@ -30,10 +34,12 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> delete<T>(StoreKey<T> key) async {
|
||||
return await transaction(() async => await _db.storeValues.delete(key.id));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> insert<T>(StoreKey<T> key, T value) async {
|
||||
return await transaction(() async {
|
||||
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 {
|
||||
final entity = (await _db.storeValues.get(key.id));
|
||||
if (entity == null) {
|
||||
@@ -49,6 +56,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
||||
return await _toValue(key, entity);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> update<T>(StoreKey<T> key, T value) async {
|
||||
return await transaction(() async {
|
||||
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* {
|
||||
yield* _db.storeValues
|
||||
.watchObject(key.id, fireImmediately: true)
|
||||
@@ -100,6 +109,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
||||
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<StoreDto<Object>>> getAll() async {
|
||||
final entities = await _db.storeValues
|
||||
.filter()
|
||||
|
||||
@@ -3,21 +3,24 @@ import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
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/presentation/pages/dev/dev_logger.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
class SyncApiRepository {
|
||||
class SyncApiRepository implements ISyncApiRepository {
|
||||
final Logger _logger = Logger('SyncApiRepository');
|
||||
final ApiService _api;
|
||||
SyncApiRepository(this._api);
|
||||
|
||||
@override
|
||||
Future<void> ack(List<String> data) {
|
||||
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> streamChanges(
|
||||
Function(List<SyncEvent>, Function() abort) onData, {
|
||||
int batchSize = kSyncEventBatchSize,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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/infrastructure/entities/exif.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' hide AssetVisibility;
|
||||
|
||||
class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
class DriftSyncStreamRepository extends DriftDatabaseRepository
|
||||
implements ISyncStreamRepository {
|
||||
final Logger _logger = Logger('DriftSyncStreamRepository');
|
||||
final Drift _db;
|
||||
|
||||
SyncStreamRepository(super.db) : _db = db;
|
||||
DriftSyncStreamRepository(super.db) : _db = db;
|
||||
|
||||
@override
|
||||
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
@@ -31,6 +34,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
@@ -53,6 +57,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
@@ -72,6 +77,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
|
||||
try {
|
||||
await _db.batch((batch) {
|
||||
@@ -95,6 +101,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||
try {
|
||||
await _deleteAssetsV1(data);
|
||||
@@ -104,6 +111,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||
try {
|
||||
await _updateAssetsV1(data);
|
||||
@@ -113,6 +121,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||
try {
|
||||
await _deleteAssetsV1(data);
|
||||
@@ -122,6 +131,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||
try {
|
||||
await _updateAssetsV1(data);
|
||||
@@ -131,6 +141,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||
try {
|
||||
await _updateAssetExifV1(data);
|
||||
@@ -140,6 +151,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||
try {
|
||||
await _updateAssetExifV1(data);
|
||||
|
||||
@@ -3,13 +3,15 @@ import 'dart:async';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:easy_localization/easy_localization.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/timeline.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
class DriftTimelineRepository extends DriftDatabaseRepository
|
||||
implements ITimelineRepository {
|
||||
final Drift _db;
|
||||
|
||||
const DriftTimelineRepository(super._db) : _db = _db;
|
||||
@@ -26,6 +28,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
return buckets;
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<Bucket>> watchMainBucket(
|
||||
List<String> userIds, {
|
||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||
@@ -46,6 +49,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
.throttle(const Duration(seconds: 3), trailing: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<BaseAsset>> getMainBucketAssets(
|
||||
List<String> userIds, {
|
||||
required int offset,
|
||||
@@ -86,6 +90,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
.get();
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<Bucket>> watchLocalBucket(
|
||||
String albumId, {
|
||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||
@@ -119,6 +124,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
||||
}).watch();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<BaseAsset>> getLocalBucketAssets(
|
||||
String albumId, {
|
||||
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/infrastructure/entities/user.entity.dart'
|
||||
as entity;
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class IsarUserRepository extends IsarDatabaseRepository {
|
||||
class IsarUserRepository extends IsarDatabaseRepository
|
||||
implements IUserRepository {
|
||||
final Isar _db;
|
||||
const IsarUserRepository(super.db) : _db = db;
|
||||
|
||||
@override
|
||||
Future<void> delete(List<String> ids) async {
|
||||
await transaction(() async {
|
||||
await _db.users.deleteAllById(ids);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteAll() async {
|
||||
await transaction(() async {
|
||||
await _db.users.clear();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
|
||||
return (await _db.users
|
||||
.where()
|
||||
@@ -35,14 +39,17 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserDto?> getByUserId(String id) async {
|
||||
return (await _db.users.getById(id))?.toDto();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<UserDto?>> getByUserIds(List<String> ids) async {
|
||||
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> insert(UserDto user) async {
|
||||
await transaction(() async {
|
||||
await _db.users.put(entity.User.fromDto(user));
|
||||
@@ -50,6 +57,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<UserDto> update(UserDto user) async {
|
||||
await transaction(() async {
|
||||
await _db.users.put(entity.User.fromDto(user));
|
||||
@@ -57,6 +65,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
||||
return user;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> updateAll(List<UserDto> users) async {
|
||||
await transaction(() async {
|
||||
await _db.users.putAll(users.map(entity.User.fromDto).toList());
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
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/infrastructure/repositories/api.repository.dart';
|
||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
class UserApiRepository extends ApiRepository {
|
||||
class UserApiRepository extends ApiRepository implements IUserApiRepository {
|
||||
final UsersApi _api;
|
||||
const UserApiRepository(this._api);
|
||||
|
||||
@override
|
||||
Future<UserDto?> getMyUser() async {
|
||||
final (adminDto, preferenceDto) =
|
||||
await (_api.getMyUser(), _api.getMyPreferences()).wait;
|
||||
@@ -18,6 +20,7 @@ class UserApiRepository extends ApiRepository {
|
||||
return UserConverter.fromAdminDto(adminDto, preferenceDto);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> createProfileImage({
|
||||
required String name,
|
||||
required Uint8List data,
|
||||
@@ -30,6 +33,7 @@ class UserApiRepository extends ApiRepository {
|
||||
return res.profileImagePath;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<UserDto>> getAll() async {
|
||||
final dto = await checkNull(_api.searchUsers());
|
||||
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);
|
||||
}
|
||||
5
mobile/lib/interfaces/local_files_manager.interface.dart
Normal file
5
mobile/lib/interfaces/local_files_manager.interface.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
abstract interface class ILocalFilesManager {
|
||||
Future<bool> moveToTrash(List<String> mediaUrls);
|
||||
Future<bool> restoreFromTrash(String fileName, int type);
|
||||
Future<bool> requestManageMediaPermission();
|
||||
}
|
||||
4
mobile/lib/interfaces/network.interface.dart
Normal file
4
mobile/lib/interfaces/network.interface.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
abstract interface class INetworkRepository {
|
||||
Future<String?> getWifiName();
|
||||
Future<String?> getWifiIp();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user